Note: This article is still useful but there is a new version with an updated API.
Let's start with a brief intro if you've never heard of lazy loading HTML images.
Lazy loading is a technique that defers image loading until it becomes visible on the screen. This saves bandwidth and can drastically improve page loading time and user experience.
There are few ways to implement lazy image loading. The most popular of them looks like this:
<img src="blank.gif" data-src="image.jpg" />
The blank.gif is a 1x1 transparent image file that loads very quickly because of it's tiny size. Then JavaScript code checks if the image is visible on the screen (after page load or page scroll) and replaces the value of the src attribute with the value of the data-src attribute. This triggers the loading of the original image. It's a very simple and powerful implementation, but it has some drawbacks.
One of the them is the lack of responsive images support. Hopefully, this can be easily fixed. The updated version looks like this:
<img src="blank.gif" data-srcset="image1.jpg 100w, image2.jpg 200w, image3.jpg 300w" />
The available image versions with their corresponding width are listed in the data-srcset attribute, and the appropriate image is selected.
Another big drawback is the blank.gif file itself. This image is bad for SEO, social networks sharing and read-it-later tools. You'll miss valuable traffic from Google Images, your posts in Facebook will not contain images (unless og:image meta tag is specified), they will not be shareable on Pinterest and the important graphics in your article will not be visible in Pocket. And again there is a fix:
<img src="small-image.jpg" data-src="image.jpg" />
The small-image.jpg file is a scaled down version of the original image. Let's say 200px in width and 10kb in size.
Loading this image is faster than loading the original image but still requires bandwidth and another HTTP request, so it's not the perfect solution.
Also, it will be great to set the image size to avoid reflowing when the original image url is set. Here is an updated version for fixed-sized images:
<img src="blank.gif" data-src="image.jpg" style="width:800px;height:600px;" />
and a version for fluid (responsive) ones:
<div style="position:relative;height:0;padding-bottom:75%;">
<img
src="blank.gif"
data-srcset="image1.jpg 100w, image2.jpg 200w, image1.jpg 300w"
style="position:absolute;top:0;left:0;width:100%;height:100%;"
/>
</div>
The best implementation
The following implementation:
- is called Responsively Lazy (available on GitHub)
- handles responsive images
- does not make ANY unnecessary requests
- works on modern browsers that support srcset. As of December 2017 that's 86.78%.
- handles loaded image resizes (when the phone is rotated from portrait to landscape). It's a nice bonus.
- does not break the page when an old browser is used
- works great in read-it-later tools like Pocket
- works great in content sharing on social networks like Facebook and Pinterest
- supports WebP
Here is an example:
<div class="responsively-lazy" style="padding-bottom:68.44%;">
<img
alt=""
src="images/2500.jpg"
srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
data-srcset="images/400.jpg 400w, images/600.jpg 600w, images/800.jpg 800w, images/1000.jpg 1000w, images/1500.jpg 1500w, images/2000.jpg 2000w"
/>
</div>
And this is how the magic happens:
- The responsively-lazy class and the padding-bottom style save space for the image and eliminate reflowing. The padding value is calculated using the following formula: imageHeight/imageWidth*100. Learn more here. A different HTML code is available at the end of the article in case you don't know the image size.
- The data:image in the srcset attribute shows a transparent image and prevents loading the image in the src attribute in modern browsers. That's the most important part.
- The image in the src is attribute is used if the browser does not support the srcset attribute or when the page is scanned by social networks and read-it-later tools.
- The data-srcset attribute contains the available image versions with their corresponding width. The best version is selected based on the space available and the device pixel ratio.
A brand new concept
Other lazy loading libraries make you break your HTML by removing the src attribute, or make you put tiny version there or make you use <noscript> to make your images appear in search engines. The following code has worked for ages:
<img src="image.jpg" />
Responsively Lazy enhances it without breaking it.
<img src="image.jpg" data-src="image-200.jpg 200w, image-400.jpg 400w" srcset="..." />
Customize
You can drop the div tag and move the responsively-lazy class name to the img tag if you don't know the image aspect ratio.
<img
alt=""
class="responsively-lazy"
src="images/2500.jpg"
srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
data-srcset="images/400.jpg 400w, images/600.jpg 600w, images/800.jpg 800w, images/1000.jpg 1000w, images/1500.jpg 1500w, images/2000.jpg 2000w"
/>
The source is available at https://github.com/ivopetkov/responsively-lazy/
So, are you ready to use lazy loading for your website's images?