Why using a library instead of native lazyloading

To lazyload or not to lazyload images? From a user and performance perspective, you should lazyload images, but should you use a JS library?

Lazyloading back in the days

Back in the days, we lazyloaded images by not setting its src-attribute, but by introducing a fake attribute holding the path to our desired image. Using JS, we can detect if the image is near the user's viewport, and load them.

When IntersectionObserver came around, things got easier. No need to check for browser resizing and less JavaScript had to be executed on the main thread. Already great performance wins.

Native lazyloading by browsers

A better solution would be, if developers didn't need to use JS at all and could rely on browsers, doing the work for them. This would reduce development-time as well. Native lazyloading was as desired, as a dark-mode amongst Stackoverflow users.

Intent to Ship: Lazily load below-the-fold images and iframes

Eventually, it happened within Chromium and native lazyloading is supported as off:

  • Chrome 76
    since July 30, 2019;
  • Edge 79 (also on Chromium nowadays),
    since January 15, 2020;
  • FireFox 75
    since April 8, 2020;
  • Opera 64
    since October 7, 2019;
  • Android Browser 80
    since Februari 18, 2020

Visit caniuse.com for current browser support. While already around for a while, FireFox is late to the party and Safari is missing altogether. Another reason why Safari is called the new Internet Explorer.

Fallback when JavaScript has been disabled

Even when JavaScript is disabled or when printing pages, images would still load as opposed to using a JavaScript library.

When using a JavaScript library, try to have a noscript fallback per image to meet those who have JavaScript disabled. Obviously, this is something that a library can't and won't do for you and has to be configured server side (for example, using a plugin that will change image attributes and creates noscript fallbacks at the same time).

Is native lazyloading a success?

When you don't have the resources to optimize your site to the fullest, then do use native lazyloading. When using Wordpress, Shopware or whatever platform for your solution, there will be plugins to implement native image lazyloading.

Although there aren't really any native lazyloading disadvantages compared to no lazyloading at all, there are some marginal notes when comparing native lazyloading with using a JavaScript library. For example:

  • Even after a year since its intent, not all browsers support lazyloading;
  • There are browser differences, where Chrome is being to eager, loading to much images in advance;
  • Native lazyloading is only supporting images and iframes, no background images, or scripts.

As lazyloading images doesn't seem to impact the crawlability of your images when it comes to GoogleBot, let's look at native lazyloading from other perspectives:

Lazyloading from a developer perspective

In a perfect world, you wouldn't need to rely on JavaScript feature detection on the client to decide whether or not a fallback library needs to be loaded, is what Addy Osmani is saying.

You would handle this before serving HTML that includes a JavaScript lazy-loading library. A Client Hint could enable such a check.

Addy Osmani

I think serving HTML based on a client hint is a good solution, because:

  • if you want to roll out lazyloading in non-supportive browsers, you would have to omit the src-attribute altogether, and only swap the attributes back to an src-attribute when native lazyloading is supported. Otherwise, let a library take over control;
  • By making HTML adaptive on the server, such a (JavaScript) check isn't needed.

However, at the same time, I see disadvantages:

  • You still need JavaScript for older browsers;
  • Doing a server check implies doing (development) work on client and server side;
  • Server side create and store different HTML caches;
  • Although not being the only performance bottleneck, newer often browsers support native lazyloading but also have less issues executing JavaScript.

Conclusion: developers don't need to do less work because of native lazyloading.

Lazyloading from a UX perspective

Native lazyloading means, you aren't in control anymore. Chrome's lazy-loading implementation is based not just on how near the current scroll position is, but also the connection speed, as revealed by its source code.

And that's a good thing, as browsers are often smarter when it comes to performance, or at least have more resources/people to evaluate behaviour. Nevertheless, there are browser differences where Chrome is more eager than FireFox, when it comes to lazyloading.

Besides internet speed, users can have Data Saving enabled. In this case, you don't want to be too eager to prevent consuming their band width. When using a library, it is up to you which strategy you wan't to follow, based on circumstances, where some libraries are already taking such circumstances into account.

Partial lazyloading support

Besides lazyloading inline images and iframes, there are other resources that could benefit from lazyloading, and thus improve performance and user experience.

Background images

Often, you want product images or hero images to be shown early on. While I would consider a product image to be critical, hero images often have cosmetic or decorative purpose and aren't critical. You could skip such resources on slow internet connections or when Data Saving has been enabled.

This means, you would still need a library to make your website and loading behaviour adaptive.

JavaScript and script tags

When it comes to performance, most developers know preventing render blocking resources is a good practice. No need to put your Google Maps script in the head section of your source code, negatively impacting Largest Contentful Paint, when the map is being displayed in the footer.

However, even then, the resources will be downloaded and executed, blocking the main thread and impacting metrics such as Time to Interactive (TTI) and the Lighthouse V6 replacement: Total Blocking Time (TBT).

Having a Google Maps, AddThis or just a sticky-element script, they often aren't critical or even resource heavy. But when not in the viewport yet, why not lazyload them. If a user never reaches the Google Maps or social sharing icons, there is no need to serve such assets.

Moreover, as above examples aren't critical resources (or at least can be replaced by just a Google Maps hyperlink, or no enriched functionality at all), a developer can even choose to omit such resources altogether, depending on the circumstances:

User preferences

Within the website my agency is building, we try to let the user overrule preferences, such as dark-mode, reduce motions and thus animations as well as download less resources. Not all users are aware of the saveData flag (called Lite mode within Chromium as off April 23, 2019) but might still want a lean experience, or just use less resources and have a lower footprint.

On the other hand, when saveData has been enabled by the user, they might choose to disable it just for one specific website. For this reason, we enable users to overrule their preferences on-site, where preferences are saved using localStorage. An example can be viewed on this website as well, via the button positioned bottom right of your screen.

To intervene in an optimal way, it is easiest to implement this type of adaptive design on the client, instead of using cookies and let the server serve a different HTML source, with different attributes. Otherwise, it would impact the setup and effectiveness of server side caching as well, if we would have to create and store different (full page) caches.

Lazyloading conclusion

Due to lack of browser support and lack of broader element/resource support, I still feel the need for using a JavaScript library. To reduce the performance impact of needed JavaScript, I adjusted an existing library to my needs, to also support background images (including webp fallback) as well as script tags.

Moreover, I know our websites are still in control of lazyloading behaviour, being more adaptive and delivering the same experience across different browsers. This would also improve trustworthiness of your data, such as bouncerates, when it comes to analyzing the effect of implementing lazyloading, or changing thresholds.

For the time being, native lazyloading isn't the one size fits all solution for me yet.