Five Ways to Lazy Load Images for Better Website Performance
With images being among the most popular type of content on the web, page load time on websites can easily become an issue.
Even when properly optimized, images can weigh quite a bit. This can have a negative impact on the time visitors have to wait before they can access content on your website. Chances are, they get impatient and navigate somewhere else, unless you come up with a solution to image loading that doesn’t interfere with the perception of speed.
In this article, you’ll learn about five approaches to lazy loading images that you can add to your web optimization toolkit to improve the user experience on your website.
What Is Lazy Loading?
Lazy loading images means loading images on websites asynchronously — that is, after the above-the-fold content is fully loaded, or even conditionally, only when they appear in the browser’s viewport. This means that if users don’t scroll all the way down, images placed at the bottom of the page won’t even be loaded.
A number of websites use this approach, but it’s especially noticeable on image-heavy sites. Try browsing your favorite online hunting ground for high-res photos, and you’ll soon realize how the website loads just a limited number of images. As you scroll down the page, you’ll see placeholder images quickly filling up with real images for preview. For instance, notice the loader on Unsplash.com: scrolling that portion of the page into view triggers the replacement of a placeholder with a full-res photo:
Why Should You Care About Lazy Loading Images?
There are at least a couple of excellent reasons why you should consider lazy loading images for your website:
- If your website uses JavaScript to display content or provide some kind of functionality to users, loading the DOM quickly becomes critical. It’s common for scripts to wait until the DOM has completely loaded before they start running. On a site with a significant number of images, lazy loading — or loading images asynchronously — could make the difference between users staying or leaving your website.
- Since most lazy loading solutions work by loading images only if the user has scrolled to the location where images would be visible inside the viewport, those images will never be loaded if users never get to that point. This means considerable savings in bandwidth, for which most users, especially those accessing the Web on mobile devices and slow-connections, will be thanking you.
Well, lazy loading images helps with website performance, but what’s the best way to go about it?
There’s no perfect way.
If you live and breathe JavaScript, implementing your own lazy loading solution shouldn’t be an issue. Nothing gives you more control than coding something yourself.
Alternatively, you can browse the Web for viable approaches and start experimenting with them. I did just that and came across these five interesting techniques.
#1 Native Lazy Loading
Native lazy loading of images and iframes is super cool. Nothing could be more straightforward than the markup below:
<img src="myimage.jpg" loading="lazy" alt="..." />
<iframe src="content.html" loading="lazy"></iframe>
As you can see, no JavaScript, no dynamic swapping of the src
attribute’s value, just plain old HTML.
The loading
attribute gives us the option to delay off-screen images and iframes until users scroll to their location on the page. loading
can take any of these three values:
lazy
: works great for lazy loadingeager
: instructs the browser to load the specified content right awayauto
: leaves the option to lazy load or not to lazy load up to the browser.
This method has no rivals: it has zero overhead, it’s clean and simple. However, although at the time of writing most major browsers have good support for the loading
attribute, not all browsers are on board yet.
For an in-depth article on this awesome feature for lazy-loading images, including browser support workarounds, don’t miss Addy Osmani’s “Native image lazy-loading for the web!”.
#2 Lazy Loading Using the Intersection Observer API
The Intersection Observer API is a modern interface that you can leverage for lazy loading images and other content.
Here’s how MDN introduces this 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 a top-level document’s viewport.
In other words, what’s being asynchronously watched is the intersection of one element with another.
Denys Mishunov has a great tutorial both on the Intersection Observer and on lazy loading images using it. Here’s what his solution looks like.
Let’s say you’d like to lazy load an image gallery. The markup for each image would look like this:
<img data-src="image.jpg" alt="test image">
Notice how the path to the image is contained inside a data-src
attribute, not a src
attribute. The reason is that using src
means the image would load right away, which is not what you want.
In the CSS, you give each image a min-height
value, let’s say 100px
. This gives each image placeholder (the img element without the src attribute) a vertical dimension:
img {
min-height: 100px;
/* more styles here */
}
In the JavaScript document, you then create a config
object and register it with an intersectionObserver
instance:
// create 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 => {
// process just the images that are intersecting.
// isIntersecting is a property exposed by the interface
if(entry.isIntersecting) {
// custom function that copies the path to the img
// from data-src to src
preloadImage(entry.target);
// the image is now in place, stop watching
self.unobserve(entry.target);
}
});
}, config);
Finally, you iterate over all of your images and add them to this iterationObserver
instance:
const imgs = document.querySelectorAll('[data-src]');
imgs.forEach(img => {
observer.observe(img);
});
The merits of this solution: it’s a breeze to implement, it’s effective, and has the intersectionObserver
do the heavy-lifting in terms of calculations.
On the flip side, although the Intersection Observer API is supported by most browsers in their latest versions, it’s not consistently supported by all of them. Fortunately, a polyfill is available.
You can learn more on the Intersection Observer API and the details of this implementation in Denys’s article.
#3 Lozad.js
A quick and easy alternative for implementing lazy loading of images is to let a JS library do most of the job for you.
Lozad is a highly performant, light and configurable lazy loader in pure JavaScript with no dependencies. You can use it to lazy load images, videos, iframes and more, and it uses the Intersection Observer API.
You can include Lozad with npm/Yarn and import it using your module bundler of choice:
npm install --save lozad
yarn add lozad
import lozad from 'lozad';
Alternatively, you can simply download the library using a CDN and add it to the bottom of the HTML page in a < script>
tag:
<script src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js"></script>
Next, for a basic implementation, add the class lozad to the asset in your markup:
<img class="lozad" data-src="img.jpg">
Finally, instantiate Lozad in your JS document:
const observer = lozad();
observer.observe();
You’ll find all the details of how you can use the library on the Lozad GitHub repository.
If you don’t want to dive into the workings of the Intersection Observer API or you’re simply looking for a fast implementation that applies to a variety of content types, Lozad is a great choice.
Only, be mindful of browser support and eventually integrate this library with a polyfill for the Intersection Observer API.
#4 Lazy Loading with Blurred Image Effect
If you’re a Medium reader, you have certainly noticed how the site loads the main image inside a post.
The first thing you see is a blurred, low-resolution copy of the image, while its high-res version is being lazy loaded:
You can lazy load images with this interesting blurring effect in a number of ways.
My favorite technique is by Craig Buckler. Here’s all the goodness of this solution:
- Performance: only 463 bytes of CSS and 1,007 bytes of minified JavaScript code
- Support for retina screens
- Dependency-free: no jQuery or other libraries and frameworks required
- Progressively enhanced to counteract older browsers and failing JavaScript
You can read all about it in How to Build Your Own Progressive Image Loader and download the code on the project’s GitHub repo.
#5 Yall.js
Yall is a feature-packed, lazy-loading script for images, videos, and iframes. More specifically, it uses the Intersection Observer API and smartly falls back on traditional event handler techniques where necessary.
When including Yall in your document, you need to initialize it as follows:
<script src="yall.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", yall);
</script>
Next, to lazy load a simple img
element, all you need to do 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 class lazy to the element
- the value of
src
is a placeholder image - the path to the image you want to lazy load is inside the
data-src
attribute
Among the benefits of Yall are:
- great performance with the Intersection Observer API
- fantastic browser support (it goes back to IE11)
- no other dependencies necessary
To learn more about what Yall can offer and for more complex implementations, feel free to check out the project’s page on GitHub.
Conclusion
And there you have it — five ways of lazy loading images you can start to experiment with and test out in your projects.
FAQs About Lazy Loading Images
Lazy loading is a web development technique used to improve the performance of web pages by deferring the loading of certain elements, such as images, until they are needed. Lazy loading images means that images are loaded only when they enter the user’s viewport or come into the visible area of the web page, rather than loading all images as soon as the page loads.
You can implement lazy loading for images in HTML using the loading
attribute. The loading
attribute is a standard HTML attribute that allows you to control when an image should be loaded. To enable lazy loading for an image, add the loading
attribute with the value “lazy” to the img
element. This tells the browser to load the image only when it is about to enter the viewport. Here’s an example:<img src="image.jpg" alt="Description" loading="lazy">
Lazy loading images is widely regarded as a beneficial practice in web development for several reasons. It enhances page loading speed by deferring non-essential image loading, resulting in faster initial page rendering and improved user experience. This approach conserves bandwidth, making it advantageous for users with limited data plans or slower internet connections. Additionally, it positively impacts search engine optimization (SEO) by boosting page loading speed, and it aligns with the principles of progressive enhancement. By reducing perceived wait times and providing visual cues during loading, lazy loading contributes to a smoother and more efficient browsing experience, particularly on mobile devices.
To determine if an image is lazy loaded on a web page, you can inspect the HTML source code or use browser developer tools. By right-clicking on the image and selecting “Inspect” or “Inspect Element,” you can examine the img
element representing the image in the developer tools panel. Look for the presence of the loading
attribute within the img
element. If the loading
attribute is set to “lazy,” it indicates that the image is configured for lazy loading. Using browser developer tools, you can quickly ascertain the lazy loading status of images by examining their attributes.