Lazy loading resources is one of the important parts of web performance tuning, simply because offscreen resources can add a lot of weight to your page if loaded eagerly.
Intro
I've gone through many tips and tricks in my image optimisation article which is one of the series I've done on web performance. However, when it comes to lazy loading, I mentioned that you have two options:
- Use
data-src
attribute on<img>
tag and hook into either ofscroll
,resize
, ororientationChange
to figure out when to replace thedata-src
withsrc
to make the call. - Use
IntersectionObserver
API to asynchronously observe the changes and make the call when the item in is the viewport.
The good news is, from Chrome 76, you can use the loading
attribute of an image tag to tell the browser how to load the image.
In fact it's so simple that you won't believe it π€―:
<img src="../path/to/image.jpg" loading="lazy">
I've created a demo to show you how it works, look closely on the network tab.
Here is a CodePen which contains the code ππ½:
.
I've just used below bash script to hack together the HTML π€·π½ββοΈ.
for i in {400..499};
> do echo "<img loading='lazy'
src='https://placedog.net/${i}/${i}' height='${i}' width='${i}' />";
> done
About the attribute
Currently the images are fetched with different priority in Chrome, the ones which are not in the viewport have less priority. But they're fetched as soon as possible regardless.
With this new loading
attribute, you can completely defer the loading of offscreen images (and iframes) to when they're reached by scrolling:
<img src="../path/to/image.jpg" loading="lazy">
<iframe src="https://placedog.net" loading="lazy"></iframe>
You can use three values with this attribute:
-
auto
: Default behaviour of the browser, equal to not including the attribute. -
lazy
: Defer loading of resources until it reaches a calculated distance from viewport. -
eager
: Load the resource immediately
My Chrome version is 76.0.3809.100
as of writing this post, but if you have any of the previous version below 76, you can activate this using flags:
- For images ππ½
chrome://flags/#enable-lazy-image-loading
- For iframes ππ½
chrome://flags/#enable-lazy-frame-loading
Feature detection
If you want to use this attribute today, you can use below code to feature detect it and have a polyfill in place such as loading-attribute-polyfill.
if ('loading' in HTMLImageElement.prototype === true) {
// use the attribute
} else {
// use polyfill
}
Prevent content reflow
Since the images are lazy loaded, if you haven't set width
and height
for your image, the content might reflow when the image is loaded and fill its place. To prevent that to happen, simply set the required values on the image tag by either style
or directly using width
and height
attributes:
<img src="../path/to/image.jpg"
loading="lazy" width="200" height="200">
<img src="../path/to/image.jpg"
loading="lazy" style="height:200px; width:200px;">
iframe loading
The same behaviour is applied to iframe
when it's used with loading
attribute. However, there are times when an iframe is hidden for analytics purposes. Examples are they are very small (less than 4px
in width and height), or they have display:none
or visibility: hidden
applied to them, or simply is offscreen using negative margin.
In these cases it won't get lazy loaded even if you have used the attribute.
What's the catch
There are few points you have to consider when using lazy loading in general. Plus there are a few things you can't do with the loading
attribute as of now.
Can't do
- You can't change the threshold to load the resource for now since it's been hard coded in the source.
- This can't be used with CSS' background image for now
Catches
- This might affect the third party ads since they will be lazy loaded too
- There will be side effect when printing π, as in the lazy loaded resources won't be printed. However, there is an open issue you can follow.
What about other browsers?
For now, Chrome is the only browser supporting this feature. Although there is an open bug for Firefox and nothing for Edge and IE.
Happy lazy loading everybody and make sure not to miss the catches ππ½.
Top comments (8)
Great writeup!
I've had trouble being sure about this as written in different places. Is the
auto
value going to be as if this feature never existed or does it mean that the browser will choose the behavior and things still might be "lazier" than they had been in the past?...does that question make sense?
I really really like this. DEV implemented this feature as soon as we possibly could.
If you enable "lazy loading" in chrome://flags, your DEV browsing experience will be moderately more efficient π
Ben Halpern γ» May 9 γ» 1 min read
I just did a quick pass to get it in some images, still need to go through more of the site and implement this in more places, especially with iframe embeds.
Thanks Ben, the auto means you are delegating the responsibility to the browser. As I mentioned, each browsers has a different way of dealing with depriotising offscreen resources, so they will use it. Also if a browser doesn't have any strategy (which is possible) then it's equal to eager
Auto, for now, will be the same as eager but the browser makers will get to choose.
github.com/whatwg/html/pull/3752/f...
'loading' in HTMLImageElement.prototype
should always returntrue
orfalse
so you shouldn't need to then compare the result totrue
like in'loading' in HTMLImageElement.prototype === true
.Does this work with divs or other elements that have overflow:auto? Or just with scrolling the body element?
Or for example modals that are in dom and have images with lazy loading attribute, but are positioned outside the view and waiting to be shown with top:0 for example?
Yes, for divs with overflow auto it will work fine. However, I am not too sure about Modals, have a look at the Distance Threshold to see how close to coming into viewport should the element be to trigger the request.
PS: If you gave it a shot for Modals, let me know and I'll update the article, that's a good one. I will try to test it myself later this week too
what about images in backgrounds ?
If you mean with CSS, that's not there yet as mentioned in the article