I recently redesigned my personal site and the first version was very lean. As I started adding content to pages and writing new blog posts, it made sense to implement image lazy-loading to improve performance.

There are many JS-based solutions for image lazy-loading but I did not want to invest time in finding the best one. So, I quickly decided to go for native lazy-loading.

Browser support for native lazy-loading is currently limited but support in Opera and Chrome is good enough for me.

Implementing native lazy-loading is easy: simply add loading="lazy" to img elements. Awesome!

I commited the change, deployed my Eleventy-powered site to Netlify and then tested how images load in Chrome. I was disappointed.

Chrome fetches all the images on my homepage on page load, while none of the images are above the fold on mobile and only some on desktop.

What is Chrome’s native image lazy-loading logic?

When does Chrome decide to fetch a below-the-fold loading="lazy" image?
Being disappointed with what I saw on my own site, I set out to find the answer to this question, like so:

  • find a very long blog post that has loading="lazy" images at the bottom: An In-Depth Tutorial of Webmentions + Eleventy
  • load the page in Chrome, then clear the Network panel
  • scroll down, a few hundred pixels at a time until those lazy-loaded images are fetched
  • in console, get the value of window.pageYOffset
  • scroll down until the top of the lazy-loaded images become visible

I see the lazy-loaded images being fetched at ~ window.pageYOffset = 8500 on desktop and they become visible at ~ window.pageYOffset = 11500. So, the image lazy-load logic of Chrome seems to be: if the image is 3000 or less pixels below the viewport, load it.

3000 pixels… that is a lot!

Load-in distance threshold

It’s always good to compare test results against the spec or official documentation.

I read the native lazy-loading explainer article on web.dev. The section Load-in distance threshold states:

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.

That section in the article also mentions the “distance threshold is not fixed and varies depending on several factors”. These factors include the type of resource being fetched (image or iframe), whether Lite mode is enabled on Chrome for Android and the effective connection type.

Thankfully, there is also a link to the relevant code in Chromium source: Lazy image loading distance-from-viewport thresholds for different effective connection types.

The code is easy to read and confirms my findings: if the effective connection type is 4g, Chrome will fetch images with loading="lazy" when they are within 3000 pixels of the current scroll position.

A Better Lazy-Loading Logic

On my 13 inch macbook, with Dock positioned on the left, the viewport height in Chrome is 786 pixels so images with loading="lazy" that are more than 4x the viewport down the page are eagerly fetched by Chrome on page load.

In my opinion, that is waaaaay too eager. Why not use a lower threshold value like 1000 pixels? Or even better: base the threshold value on the actual viewport height.

I will file a bug with Chromium soon and see where that leads.

If I would need to implement image lazy-loading on a high-traffic e-commerce site today, I’d very likely go for a JS-based solution. Partly because the native solution only works in Chrome, but also because Chrome’s implementation is too eager and therefore not so effective.

ABOUT THE AUTHOR

Aaron Peters photo

Aaron Peters (@aaronpeters) is a freelance web performance consultant since 2009 and co-founder of Multi-CDN provider TurboBytes and CDN Planet.

9 Responses to “Native Image Lazy Loading in Chrome Is Way Too Eager”

  1. Barry

    Nice investigation but I’m not sure I agree to be honest. One of the things I hate about lazy loading is the noticeable delay when scrolling down so think there is a balance. This is respectably true on fast computers/connections where lazy loading can actually make a site feel slower – surely the opposite of the intention of this feature!

    By taking the Effective Connection Type into account I think they strike a good balance here and 4G connection or higher suggests plenty of bandwidth (though admittedly nothing to say the cost of that bandwidth!) and think it should be quite eager in that case to avoid the first point I made.

  2. Dario

    Yeap, I also reached the same conclusion, in our case we left the native lazyload for images that need to be indexed (as SEO strategy), and continue to use the javascript lazyload for all the rest since gives me more control over the thresholds. I don’t understand why Chrome does not give some override control to the developers since only a bunch of us that knows what this is are going to use it anyway.
    Is there any way to vote your “bug/lack of feature” in Chrome to be voted? Thanks!

  3. Aaron Peters

    @Barry “… One of the things I hate about lazy loading is the noticeable delay when scrolling down …” . I feel the same, so the challenge is to implement a logic / thresholds that find optimal balance and imho Chrome does not have that today. Lower thresholds, e.g. 3000 becomes 1500, should be just as good for most user experiences but a lots less data is fetched early.
    The cost of the bandwidth is something we should not take lightly. I know many people who have fast 4G on their phones but also a limited, small data plan (1 GB/m).

  4. Aaron Peters

    @Dario, why does Chrome not allow devs to set their own thresholds for their website? Well, one argument can be: Keep It Simple. Don’t let devs even think about the thresholds. On the other hand, the self-set thresholds can be option.

    I will post a comment here, and on Twitter, once I filed the bug report with Chromium.

  5. Alena Mage

    Yes, sometimes I also feel about lazy loading issues. That’s the way chrome is way to eager and enhance.

  6. Karl

    I guess when Google puts that much emphasis on making websites appear as fast as possible to all visitors through various mechanisms (critical css, ttf, dns preload, cdn, http/2), it’s kinda counter-productive if they didn’t also preload a generous amount of images after page load, to be available on scroll.

    Let’s face it. If you are on a standard modern wifi connection, it’s unlikely you would see any negative effects of a website loading images 3000 px below the viewport.

  7. Mikael Gramont

    I see here that there are several factors that Chrome takes more than just page offset into account: https://web.dev/native-lazy-loading/

    I couldn’t find any reference to a standard for how this works though, it kind of looks like Google is out there doing their own thing. Which would suck because you can pretty much assume Safari will behave totally differently for business reasons, and Firefox will be doing something else too.

    This is a complex problem, and I don’t think a single algorithm will suit everyone’s needs. We’d benefit from listing the different scenarios and corresponding user expectations before making assessments.

    For example, I see people mention the fact that they are annoyed by the fact that they load up a page and get on a train without network coverage, scroll and see missing images. Others say they hate seeing images being rendered as they are still loading.

    I’d love to see a standard list of scenarios, with matching browser behaviors that could be triggered by sending a response header or meta. Things like:

    x-lazy-load-minimal => careful lazy-load images, low distance threshold
    x-lazy-load-eager => less careful lazy-load images, higher distance threshold
    x-lazy-load-disable => disable lazy-loading, load everything as usual

  8. Native Image Lazy Loading in Chrome Is Way Too Eager – Bram.us

    […] Native Image Lazy Loading in Chrome Is Way Too Eager → […]

  9. Les tendances et les défis webperf pour 2020 - Fasterize

    […] si cette première implémentation de Chrome est sujette à débat, les premières pierres de l’édifice sont en […]

Leave a Reply

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
And here's a tool to convert HTML entities