About lazy-loading and why you should use it
The worldwide web has evolved over the past decades and today's websites consist not only of text and color, but also of countless media content. First and foremost images.
<img src="/path/to/your/image.jpg" alt="Awesome image" />
But what does this have to do with lazy-loading?
Lazy-loading is a technique that defers loading of non-critical resources at page load time. Instead, these non-critical resources are loaded at the moment of need. Where images are concerned, "non-critical" is often synonymous with "off-screen".
-- from web.dev/lazy-loading written by Jeremy Wagner and Rachel Andrew
This means by using lazy-loading we achieve the following benefits over the classic embedding in HTML:
- Performance Gains - With lazy-loading we can improve loading speed by reducing the number of images that need to be loaded initially.
- Cost reduction - A lazy loaded image may never need to load because the user never reaches the image's position on the page.
Ok, sounds good. How can we make that happen? What do we need for this? Let's get started!
The old (Javascript) approach
There are a lot of snippets and scripts like vanilla-lazyload out there that enable lazy-loading via javascript. In almost all cases a data attribute is used to prevent upfront image loading.
html
<img data-src="/path/to/your/image.jpg" alt="Awesome image" />
But how is the image loaded at all? To achieve this, one of the following two techniques is usually used.
Event listeners
This technique uses event listeners on the scroll, resize and orientationChange events in the browser. If one of the mentioned events is fired and assuming the image enters the viewport the data-src attribute is replaced with the src attribute to trigger the loading call. See it in action:
Intersection Observer API
Unlike the first method, the image is observed (asynchronously) by using the IntersectionObserver API. The image is then loaded by changing the data-src
to src
attribute as soon as it enters the viewport.
But what if I told you that you don't need Javascript at all? 😲 Yes, you heard right! Zero Javascript.
The new (HTML) approach
So what does this new way of lazy-loading look like? No worries, it's perfectly simple. You just have to add loading="lazy"
to your image tag and that's it. 😎
<img src="/path/to/your/image.jpg" loading="lazy" />
With this new loading attribute, you can completely defer the loading of offscreen images (and even iframes in some browsers) to when they enter the viewport. Enough talking, let's see it in action!
The attribute comes with three values:
- auto - (Default) equal to not including the attribute.
- lazy - Defer loading of resources until it enters the viewport.
- eager - Load the resource immediately
What about browser support?
The attribute is supported by almost every popular browser (Chrome, Edge, Opera and Firefox). The implementation for Safari is in progress and almost done. If you need more detailed information on cross-browser support caniuse.com is your friend.
What happens if a browser does not support the attribute?
Browsers that do not support the loading attribute simply ignore it without any side-effects. Fortunately, there is a polyfill at Github available named loading-attribute-polyfill which can be used in those cases.
if ('loading' in HTMLImageElement.prototype) {
// Cool! The browser supports the loading attribute
} else {
// Houston... We need a polyfill!
}
Are there any limitations?
Even though it is pretty cool to let the browser do the lazy-loading work, you should be aware of some limitations that come into play when using the attribute:
- Unlike the Javascript variants, you do not have any influence on the threshold to load the resource. It is part of the browser code and can't be changed for now.
- The attribute can't be used in combination with CSS background images. Maybe it will come in near future but it is definitely not available now.
- If printing the webpage is a real usecase for you, then please notice that there is an open bug for the loading attribute.
If you liked this post, please give me a ❤️ or even a 🦄 and feel free to follow me on dev.to
. Appreciate it! ✌️
Top comments (23)
As a sidenote,
loading=“lazy”
only works if JavaScript is enabled, which for me seemed a bit weird - until I read this at MDN:Loading is only deferred when JavaScript is enabled. This is an anti-tracking measure, because if a user agent supported lazy loading when scripting is disabled, it would still be possible for a site to track a user's approximate scroll position throughout a session, by strategically placing images in a page's markup such that a server can track how many images are requested and when.
To test, disable JavaScript in DevTools (
Shift + Command + P > Disable JavaScript
), go to the Network Tab and refresh the page. All images will load instantly.Interesting, didn't know that. Thanks for mentioning, Mads!
Link where that's found:
developer.mozilla.org/en-US/docs/W...
Probably worth mentioning that this is best used for images which aren't going to be visible on page load. I've actually observed page performance in Lighthouse, and in turn Google's search console ranking, drop if there are too many images "above the fold" using
loading="lazy"
as it detects it as a longer initial load time.It's a great feature though, definitely good for articles or long marketing pages.
Good point, Andrew! I will take that into account in future. Thanks for pointing out.
Great to know! Going to implement this on my personal page right after work and see how it goes
I wish I could report how great it worked for me, and how I was able to remove another 3rd party dependency from my site. Unfortunately, Vue 2 just doesn't get it and loads the images anyway. I tested it out on a "basic" site and it worked fantastic, however, if you are running a "framework"... in my case, Vue.. mileage may vary
That's probably because parts of the DOM gets re-written. You could try
<img data-src="your-image" loading="lazy" />
, and then setimg.src = img.dataset.src
, when the component has been mounted in Vue.Looks like a mixture from both worlds (see above in the article). As a disclaimer: I haven't give Vue.js a try. Should I? 🤔
Mads I might have to, thanks! I've been using a combination of Intersection observers, and a plugin, Vue.LazyLoad to handle the late binding of images on my page. It's just disappointing to see native HTML not render like you'd expect to see, but that might be one of the sacrifices you give up when using a framework.
Paul. Since Im just starting out with JS frameworks, I started with Vue. It is growing in popularity, however, React and Angular are still kings at this time.
Luke. I am very familiar with React, Angular and even Ember. But I haven't had the chance to look into Vue.js yet.
How it went?
Awesome! Maybe you can share your feedback how it worked for you. 👍
Not great for safari
Safari, worst browser after IE 🤬
True words. So sad. 😁
Hi Brian! What do you mean by that?
just that the native lazy attribute on the image tag is not supported out of the box on Safari (it's an experimental item). I've had to implement alternative solutions for lazy as a result.
Yes, agree! That's is a little bit annoying. With luck, it might not be that long before we can use it natively here, too. Fingers 🤞!
Everything is #SEO: users and Google are happy.
That is absolutely correct! 😄
Great post
Thanks, Ben! Glad that you like it. 😊