Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy loading with "responsive" images (unknown height)

I'm using a CSS grid system which is based upon percentages. I have a grid with 4 columns, each 25% of the page's total width. I output my image tags inside of each "25% cell" like this:

<img src="foo.jpg" style="max-width:100%" />

As the browser resizes, the images also resize to fill in 100% of each 25% cell. The browser picks a height, as if I had put "height:auto" (which is implicit when omitted).

Now I want to add lazy loading capability to this. The problem is that before the images are loaded, their height on the page is unknown. The browser has to download the image & observe its aspect ratio, and calculate a height for it. Prior to this, all the images have a height of 1px. Since every image has a height of 1px, they are all considered as "within the viewport" and are immediately loaded.

Currently I have a proof of concept where prior to outputting the img tag, I calculate the images aspect ratio on the server, and output in a data attribute:

<img src="foo.jpg" style="max-width:100%" data-aspect="1.7742" />

Then, upon the event "document ready", I loop through every image and set a fixed 'height' value in pixels prior to lazy loading:

$('img').each(function() {
        var img = $(this);
        var width = img.width();
        var ratio = img.data('aspectratio');
        var height = width / ratio;
        $(this).css('height', height+'px');
    });

This seems to be working, in the sense that it no longer loads all the images at the same time, but only loads images as I scroll.

However, it seems like it could cause new problems, like the images becoming stretched as the user resizes the browser. I would have to switch the 'height' back to 'auto' when a callback fires for lazy loading having completed. That would take care of images the user sees - but the images below the fold would still have an improper 'height' value upon the browser being resized. Every time the browser is resized, I would have to iterate all images that were previously below the fold, measure their updated width, read their aspect ratio, and update the new height, and then retrigger lazy loading to handle anything that is now above the fold. If I don't do this, loading could be triggered too early or too late due to those images having the wrong height value.

My question is, is there any other ways to lazy load images with unknown heights, other than the exact method I've described here, and what ramifications would this have? Is there any downside to my method, other than it being a pain to program?

like image 806
Josh Ribakoff Avatar asked May 01 '14 21:05

Josh Ribakoff


People also ask

Can you Lazyload background images?

While <img> tags are the most common way of using images on web pages, images can also be invoked via the CSS background-image property (and other properties). Browser-level lazy-loading does not apply to CSS background images, so you need to consider other methods if you have background images to lazy-load.

What is Lazyload image?

Lazy Loading Images is a set of techniques in web and application development that defer the loading of images on a page to a later point in time - when those images are actually needed, instead of loading them up front.

What is content reflow?

Reflow is the name of the web browser process for re-calculating the positions and geometries of elements in the document, for the purpose of re-rendering part or all of the document.

What is Shopify lazy loading?

Lazy loading is one such way to optimize Shopify sites for speed. Lazy loading increases browser response to fast loading pages since it's not loading all the images right away. Thus, lazy loaded images don't contribute to the initial page load and show many great benefits such as: Make site lighter and faster.


1 Answers

I had a similar problem recently, combining Isotope with Lazy Load in a responsive layout. Isotope determines the layout based upon the width and height of the images when the page is loaded, so initially, the items were all overlapping because Isotope wasn't calculating the correct size.

To make sure the placeholder items were saving the space, I used the padding-bottom trick you mentioned: http://thisisthat.co.uk/notebook/2013-10-07-lazy-loading-responsive-images (Though it may have not been that exact post.) Here's my markup:

    <article class="portfolio-item">
        <a class="portfolio-link" href="img/gallery/thumb90.jpg" style="padding-bottom: 66.2%">
            <div class="portfolio-image-wrapper">
                <img class="portfolio-image" data-original="img/gallery/thumb90.jpg" width="1000" height="662">
            </div>
            <div class="portfolio-text">
                <h1 class="portfolio-item-name">
                    <span href="#" class="icon" data-icon="e"></span>
                    <span class="portfolio-item-tags">Bridals</span>
                </h1>
            </div>
        </a>
    </article>

That's probably more involved than you need (as the entire .portfolio-text div is an overlay which has quite a bit of styling going on). The real key was just in calculating the bottom padding based upon the width and height of the image (which I did in the template with PHP) and setting that as the padding-bottom of the item that I wanted to save the space.

like image 115
jpsingleton Avatar answered Sep 30 '22 17:09

jpsingleton