Anyone familiar with front-end performance knows that using images efficiently is a big deal. By adjusting the size or compression (or format) of an image, you can see instant benefits. But what do you do when you have a large number of images to display on a page, and although they each may be fairly small, collectively they represent a huge amount of data that needs to be transferred over the wire?
- One option would be to reevaluate if the images are truly necessary, and get rid of some (or all) of them.
- Another option would be to just deal with the performance hit, and not worry about it.
- But if neither of these seem appealing, there is a middle way: Lazy Loading.
What Is Lazy Loading?
When loading images, ‘lazy loading’ refers to a technique where we only load the assets as they are needed. So when a user first hits the page, we would only load the images on the initial screen (and maybe just beyond it). Then, as the user scrolls, we would load subsequent images on the page as they come into view. The user will still see all of the images if they continue down the page, but we’re not forced to load them all unless necessary.
Why Should You Lazy Load?
By delaying the loading of images, both the user and the webpage save bandwidth on transferring images that were loaded but never needed. This is espcially relevant when users are connecting over a mobile network. And since the page doesn’t have to load all these files up front, it will load faster, giving the user a better experience when they first hit the page.
How to Implement
Conceptually, the concept is pretty straightforward: As the user scrolls down the page, we utilize JS to check if images are entering the visible area of the page. Once they are visible, or are within a predefined distance of being visible, the proper source for that image is loaded. Loading the images a little before they hit the bottom of the screen helps ensure that the images are fully loaded by the time the user gets to them.
Typically, the markup for lazy loading utilizes a data attribute in the image tag to hold the original source (the one that will eventually get loaded), and then either a blank image or some kind of placeholder for the default state. Sometimes, you may also use a class to specify which images will be lazyloaded.
For instance, depending on the JS you use, you may end up with an
<img> tag that looks something like this:
<img src="blank.png" data-src="my-image.jpg" class="lazyload" alt="My Image">
When it comes to implementing the JS to actually load the images, you have two options:
- Either write your own JS to do it
- Use JS that someone else has written
Writing your own is certainly a fine way to go. But depending on the situation, it may be more advantageous to make use of some of the plugins that other smart people have already spent their precious time creating. Instead of going into the details of writing your own code, here’s a list of a few popular and/or useful plugins I’ve found:
- Lazysizes is a library I’ve used multiple time and have found helpful. It works with
srcset, and the additional extension unveilhooks is great in working with background-images you want to lazy load.
- Lazy Load Plugin for jQuery has been around awhile, and is a classic plugin if you’re already using jQuery.
- Unveil.js was inspired by lazyload.js, but is extremely lightweight. It also builds upon jQuery or Zepto, and can be useful if you are looking for something minimal.
Even if you do end up writing your own, looking at these as examples can be beneficial, and can help you understand different techniques that can be used to achieve the results you’re looking for.
JS Turned Off
But what if JS isn’t turned on? If all of the images are lazy loaded, and lazy loading required JS, a lack of JS would cause none of them to show up.
This is a possibility. But there are some ways to alleviate this potential issue. One simple way is to provide a
<img src=“blank.png” data-src=“my-real-image.jpg” alt=“My Real Image”> <noscript><img src=“my-real-image.jpg” alt=“My Real Image”></noscript>
This will ensure that if there is no JS, the images will still be loaded.
Another possibility is that JS is enabled, but there’s an error elsewhere in the code the keeps the lazy loading process from running properly. In a recent article, Robin Osborne looks at ways to mitigate this risk, and make sure lazy loading is not totally dependent on JS.
One way to do so is to not lazy load the images on the initial screen — that way they will be loaded regardless of whether JS is working or not.
Another technique is to also set up a separate copy of the page that can be used to display the images without the use of lazy loading. On the initial page, there could be a link to this page with the non-lazy loaded content. Then, if the JS is working properly, we hide this link and lazy load the rest of the images. But if there is a JS error that prevents lazy-loading, then this link stays visible, and can be used by the user to view the images.
Lazy loading isn’t a cure all, but it can help performance. It will cost you a few extra kB of JS or extra markup, but it could also save you 100s, or even 1,000s of kB in all the images that don’t end up getting loaded.
Images can be an important part of the user experience. And so is how quickly a page loads. Lazy loading is a good way to integrate both. It enables the use of several images on a page, while at the same time doing so in a smart, efficient way that keeps our pages loading quickly.