Phone outline with loading image and assets

Native lazy-loading for the web

Browser-level native lazy-loading is finally here!

Houssein Djirdeh
Houssein Djirdeh
Addy Osmani
Addy Osmani
Mathias Bynens
Mathias Bynens

Support for natively lazy-loading images and iframes is coming to the web! This video shows a demo of the feature:

Starting with Chrome 76, you'll be able to use the new loading attribute to lazy-load resources without the need to write custom lazy-loading code or use a separate JavaScript library. Let's dive into the details.

Why native lazy-loading?

According to HTTPArchive, images are the most requested asset type for most websites and usually take up more bandwidth than any other resource. At the 90th percentile, sites send about 4.7 MB of images on desktop and mobile. That's a lot of cat pictures.

Embedded iframes also use a lot of data and can harm page performance. Only loading non-critical, below-the-fold images and iframes when the user is likely to see them improves page load times, minimizes user bandwidth, and reduces memory usage.

Currently, there are two ways to defer the loading of off-screen images and iframes:

Either option can let developers include lazy-loading functionality, and many developers have built third-party libraries to provide abstractions that are even easier to use. With lazy-loading supported directly by the browser, however, there's no need for an external library. Native lazy loading also ensures that deferred loading of images and iframes still works even if JavaScript is disabled on the client.

The loading attribute

Today, Chrome already loads images at different priorities depending on where they're located with respect to the device viewport. Images below the viewport are loaded with a lower priority, but they're still fetched as soon as possible.

In Chrome 76, you can use the loading attribute to completely defer the loading of offscreen images and iframes that can be reached by scrolling:

<img src="image.png" loading="lazy" alt="" width="200" height="200">
<iframe src="https://example.com" loading="lazy"></iframe>

Here are the supported values for the loading attribute:

  • auto: Default lazy-loading behavior of the browser, which is the same as not including the attribute.
  • lazy: Defer loading of the resource until it reaches a calculated distance from the viewport.
  • eager: Load the resource immediately, regardless of where it's located on the page.

The feature will continue to be updated until it's launched in a stable release (Chrome 76 at the earliest). But you can try it out by enabling the following flags in Chrome:

  • chrome://flags/#enable-lazy-image-loading
  • chrome://flags/#enable-lazy-frame-loading

Load-in distance threshold

All images and iframes that are above the fold—that is, immediately viewable without scrolling—load normally. Those that are far below the device viewport are only fetched when the user scrolls near them.

The distance threshold is not fixed and varies depending on several factors:

You can find the default values for the different effective connection types in the Chromium source. These numbers, and even the approach of fetching only when a certain distance from the viewport is reached, may change in the near future as the Chrome team improves heuristics to determine when to begin loading.

In Chrome 77, you can experiment with these different thresholds by throttling the network in DevTools. In the meantime, you will need to override the effective connection type of the browser using the chrome://flags/#force-effective-connection-type flag.

Image loading

To prevent the surrounding content from reflowing when a lazy-loaded image is downloaded, make sure to add height and width attributes to the <img> element or specify their values directly in an inline style:

<img src="..." loading="lazy" width="200" height="200">
<img src="..." loading="lazy" style="height:200px; width:200px;">

Images will still lazy-load if dimensions are not included, but specifying them decreases the chance of browser reflow.

Support for the intrinsicsize attribute is also being worked on, so images will lazy-load correctly if intrinsicsize is specified along with one other dimension (width or height).

<img src="" alt="" loading="lazy" intrinsicsize="250x200" width="450">
<!-- lazy-loaded -->

Take a look at this demo to see how the loading attribute works with 100 pictures.

iframe loading

The loading attribute affects iframes differently than images, depending on whether the iframe is hidden. (Hidden iframes are often used for analytics or communication purposes.) Chrome uses the following criteria to determine whether an iframe is hidden:

  • The iframe's width and height are 4 px or smaller.
  • display: none or visibility: hidden is applied.
  • The iframe is placed off-screen using negative X or Y positioning.

If an iframe meets any of these conditions, Chrome considers it hidden and won't lazy-load it in most cases. Iframes that aren't hidden will only load when they're within the load-in distance threshold. A placeholder shows for lazy-loaded iframes that are still being fetched.

FAQ

Are there plans to expand this feature?

There are plans to change the default lazy-loading behavior of the browser to automatically lazy-load any images or iframes that are well suited to being deferred if Lite mode is enabled on Chrome for Android.

Can I change how close an image or iframe needs to be before a load is triggered?

These values are hardcoded and can't be changed through the API. However, they may change in the future as the Chrome team experiments with different threshold distances and variables.

Can CSS background images take advantage of the loading attribute?

No, it can currently only be used with <img> tags.

How does the loading attribute work with images that are in the viewport but not immediately visible (for example, behind a carousel)?

Only images that are below the device viewport by the calculated distance load lazily. All images above the viewport, regardless of whether they're immediately visible, load normally.

What if I'm already using a third-party library or a script to lazy-load images or iframes?

The loading attribute should not affect code that currently lazy-loads your assets in any way, but there are a few important things to consider:

  1. If your custom lazy-loader attempts to load images or frames sooner than when Chrome loads them normally—that is, at a distance greater than the load-in distance threshold— they are still deferred and load based on normal browser behavior.
  2. If your custom lazy-loader uses a shorter distance to determine when to load a particular image or iframe than the browser, then the behavior would conform to your custom settings.

One of the important reasons to continue to use a third-party library along with loading="lazy" is to provide a polyfill for browsers that do not yet support the attribute.

Do other browsers support native lazy-loading?

The loading attribute can be treated as a progressive enhancement. Browsers that support it can lazy-load images and iframes. Those that don't yet can load images just like they would today. In terms of cross-browser support, loading should be supported in Chrome 76 and any Chromium 76-based browsers. There is also an open implementation bug for Firefox.

A similar API was proposed and used in IE and Edge but was focused on lowering the download priorities of resources instead of deferring them entirely. It was discontinued in favour of resource hints.

How do I handle browsers that don't yet support native lazy-loading?

Create a polyfill or use a third-party library to lazy-load images on your site. The loading property can be used to detect if the feature is supported in the browser:

if ('loading' in HTMLImageElement.prototype) {
// supported in browser
} else {
// fetch polyfill/third-party library
}

For example, lazysizes is a popular JavaScript lazy-loading library. You can detect support for the loading attribute to load lazysizes as a fallback library only when loading isn't supported. This works as follows:

  • Replace <img src> with <img data-src> to avoid an eager load in unsupported browsers. If the loading attribute is supported, swap data-src for src.
  • If loading is not supported, load a fallback (lazysizes) and initiate it. As per lazysizes docs, you use the lazyload class as a way to indicate to lazysizes which images to lazy-load.
<!-- Let's load this in-viewport image normally -->
<img src="hero.jpg" alt="">

<!-- Let's lazy-load the rest of these images -->
<img data-src="unicorn.jpg" alt="" loading="lazy" class="lazyload">
<img data-src="cats.jpg" alt="" loading="lazy" class="lazyload">
<img data-src="dogs.jpg" alt="" loading="lazy" class="lazyload">

<script>
if ('loading' in HTMLImageElement.prototype) {
const images = document.querySelectorAll('img[loading="lazy"]');
images.forEach(img => {
img.src = img.dataset.src;
});
} else {
// Dynamically import the LazySizes library
const script = document.createElement('script');
script.src =
'https://cdnjs.cloudflare.com/ajax/libs/lazysizes/4.1.8/lazysizes.min.js';
document.body.appendChild(script);
}
</script>

Here's a demo of this pattern. Try it out in a browser like Firefox or Safari to see the fallback in action.

The lazysizes library also provides a native loading plugin that uses native lazy-loading when available but falls back to the library's custom functionality when needed.

How does native lazy-loading affect advertisements on a web page?

All ads displayed to the user in the form of an image or iframe lazy-load just like any other image or iframe.

How are images handled when a web page is printed?

Although the functionality isn't in Chrome 76, there's an open issue to ensure that all images and iframes are immediately loaded if a page is printed.

Conclusion

Baking in native support for lazy-loading images and iframes can make it significantly easier for you to improve the performance of your web pages.

Are you noticing any unusual behavior with this feature enabled in Chrome? File a bug!

Last updated: Improve article