
Images are one of the most common content types on the web, which makes page load time an easy problem to run into.
Even when they are properly optimised, images can still be heavy. That weighs on how long visitors have to wait before they reach the content of your site. Chances are they will lose patience and browse elsewhere, unless you find a way of loading images that does not get in the way of perceived speed.
In this article you will find five approaches to lazy loading images that you can add to your web optimisation toolbox to improve the user experience on your site.
What is lazy loading?
Lazy loading images means loading them asynchronously, in other words once the content above them has finished loading, or even conditionally, only when they appear in the browser viewport. So if users never scroll to the bottom of the page, the images sitting down there are never loaded at all.
Plenty of websites work this way, but it shows most on image-heavy sites. Browse your favourite hunting ground for high-resolution photos and you will quickly notice that the site only loads a limited number of images. As you scroll, you will see the placeholders fill in with the real images for the preview. Watch how Unsplash.com loads: scrolling that part of the page into view is what swaps a placeholder for a full-resolution photo.
Why should you care about lazy loading images?
There are at least two very good reasons to consider lazy loading the images on your site:
- If your site uses JavaScript to display content or provide any kind of feature to users, DOM loading quickly becomes critical. Scripts commonly wait for the DOM to be fully loaded before they start running. On a site carrying a large number of images, lazy loading, or loading images asynchronously, can be the difference between users staying and users leaving your site.
- Since most lazy loading solutions only load an image once the user has scrolled to the point where it would be visible in the viewport, those images are never loaded if users never get there. That means substantial bandwidth savings, and most users will thank you for them, especially the ones browsing on mobile devices and slow connections.
Lazy loading images helps the performance of a site, but what is the best way to go about it?
There is no perfect method.
If you live and breathe JavaScript, writing your own lazy loading solution should be no trouble. Nothing gives you more control than coding something yourself.
You can also search the web for workable approaches and start experimenting with them. That is what I did, and I came across these five interesting techniques.
#1 Native lazy loading
Native lazy loading for images and iframes is very neat indeed. Nothing could be simpler than the markup below:
<img src="myimage.jpg" loading="lazy" alt="..." />
<iframe src="content.html" loading="lazy"></iframe>
As you can see, there is no JavaScript, no dynamic swapping of the image and iframe src, just good old HTML.
The loading attribute lets you defer offscreen images and iframes until users scroll down to their place on the page. loading takes one of three values:
lazy: works nicely for lazy loadingeager: tells the browser to load the given content immediately.auto: leaves it to the browser to decide whether to lazy load or not.
This method has no rival: no overhead, clean and simple. That said, while most major browsers now have solid support for the loading attribute as of this writing, not every browser is on board yet.
#2 Lazy loading with the Intersection Observer API
The Intersection Observer API is a modern interface you can use to lazy load images and other content.
Here is how MDN introduces the API:
The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with the viewport of a top-level document.
In other words, what is observed asynchronously is the intersection of one element with another.
Say you want to lazy load an image gallery. The markup for each image would look like this:
<img data-src="image.jpg" alt="test image">
Notice that the path to the image sits in a data-src attribute rather than a src attribute. The reason is that using src would load the image immediately, which is not what you want.
In the CSS, give every image a min-height of, say, 100px. That gives each image slot (the img element without its src attribute) a vertical dimension:
img {
min-height: 100px;
/* more styles here */
}
In the JavaScript, you then create a config object and register it with an intersectionObserver instance:
// create a config object: rootMargin and threshold
// are two properties exposed by the interface
const config = {
rootMargin: '0px 0px 50px 0px',
threshold: 0
};
// register the config object with an instance
// of intersectionObserver
let observer = new intersectionObserver(function(entries, self) {
// iterate over each entry
entries.forEach(entry {
// only handle the images that are intersecting.
// isIntersecting is a property exposed by the interface
if(entry.isIntersecting) {
/. / Fonction personnalisée qui copie le chemin vers l'image
// from data-src to src
preloadImage(entry.target);
// the image is in place now, stop watching
self.unobserve(entry.target);
}
});
}, config);
Finally, iterate over all your images and add them to that iterationObserver instance:
const imgs = document.querySelectorAll('[data-src]');
imgs.forEach(img {
observer.observe(img);
});
The upsides of this solution: it is easy to implement, it is efficient, and it leaves intersectionObserver to do the heavy lifting on the calculations.
On the other hand, while the Intersection Observer API is supported by most browsers in their latest versions, it is not supported consistently across every browser. Fortunately, a polyfill is available.
#3 Lozad.js – lazy loading in JS
A quick and easy alternative for lazy loading images is to let a JS library do the heavy lifting for you.
Lozad is a very fast, lightweight and configurable lazy loader written in plain JavaScript, with no dependencies at all. You can use it to lazy load images, videos, iframes and much more, and it builds on the Intersection Observer API.
You can pull Lozad in with npm or Yarn and import it with the module bundler of your choice:
npm install --save lozad
yarn add lozad
import lozad from 'lozad';
You can also load the library from a CDN and add it at the bottom of the HTML page in a < script> tag:
<script src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js"></script>
Then, for a basic implementation, add the lozad class to the asset in your markup:
<img class="lozad" data-src="img.jpg">
Finally, instantiate Lozad in your JS file:
const observer = lozad();
observer.observe();
All the details on how to use the library are on the Lozad GitHub repository.
If you would rather not dig into the inner workings of the Intersection Observer API, or you are simply after a quick implementation that covers a variety of content types, Lozad is an excellent pick.
Just keep an eye on browser support, and pair the library with a polyfill for the Intersection Observer API if you need one.
#4 Lazy loading with a blurred image effect
The first thing you see is a blurred, low-resolution copy of the image, while the high-resolution version is lazy loaded:


There are several ways to lazy load images with this rather nice blur effect.
Here is everything this solution has going for it:
- Performance: only 463 bytes of CSS and 1,007 bytes of minified JavaScript.
- Support for retina screens
- No dependencies: no need for jQuery or any other library or framework.
- Progressive enhancement, to cover older browsers and JavaScript that fails to run.
To get that kind of effect, you can download progressive-image.js.
#5 Yall.js – lazy loading in JS
Yall is a feature-rich lazy loading script for images, videos and iframes. It builds on the Intersection Observer API and falls back intelligently on traditional event handling when it has to.
Once Yall is included in your document, you need to initialise it like this:
<script src="yall.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", yall);
</script>
Then, to lazy load a simple img, all you need in your markup is:
<img class="lazy" src="placeholder.jpg" data-src="image-to-lazy-load.jpg" alt="Alternative text to describe image.">
Note the following:
- you add the lazy class to the element
- the value of
srcis a placeholder image - the path to the image you want to lazy load lives in the
data-srcattribute
The upsides of Yall include:
- great performance thanks to the Intersection Observer API
- excellent browser support (it goes all the way back to IE11)
- no other dependency needed
To learn more about what Yall has to offer, and for more involved implementations, have a look at the project on GitHub.
Conclusion
There you have it – five ways of lazy loading images that you can start experimenting with and testing in your own projects.


