07 November 2019
Lazy loading – a simple method to speed up loading time and improve website’s UX
What’s Lazy loading? It’s a design pattern that can effectively speed up your websites and applications by deferring loading non-critical resources. Instead of loading content at page load, it is being loaded when needed (that’s why some people call lazy loading “on-demand loading”). Thanks to this simple principle of operation, it can be used in almost every kind of web and mobile apps. In this article, I’m gonna tell you how to implement lazy loading images in your projects.
Browsers try their best to optimize loading pipeline by analyzing DOM tree and determining what can they skip while doing the initial render. They use various techniques to achieve that – for example by ignoring elements that have display: none;
. However, it’s often unpredictable, especially with Single-Page-Applications where JavaScript generates DOM elements. That’s the main reason why we need to help browsers to tell what users see first.
Note: If you’re looking for the new Lazy Loading HTML loading
attribute for img
and iframe
tags introduced in recent Chrome versions, make sure to check out my next article: “The new native lazy loading for images and iframes in Chromium-based browsers”! 😁
"The new native lazy loading for images and iframes in Chromium-based browsers
Introducing the loading problem
Modern websites are full of various images and videos, making them more appealing to a user. It’s an important part – visual elements attract attention from the first time the user loads a web page and can tell more and much quicker than blocks of text. While being an excellent method of telling a story, graphic visuals weight a lot, and each of them increases page load time. Basing on HTTPArchive report, at the 90th percentile sites send on average 6.9MB of data, where over 4.7MB of that are just images. The conclusion is simple, the heavier the web page is, the slower the loading.
My workmates have already written on improving applications’ accessibility for disabled users and how to cut down flashy effects to make animations more user-friendy. Unfortunately, sometimes getting rid of media from a web page is often a no-go, and there’s a need for another solution to this problem.
Luckily, lazy loading is a way to go – it lowers the load time, allows showing the content quicker, but it doesn’t require to make any cuts in graphics.
Principle of operation
Lazy Loading defers fetching non-critical resources at page load time and waits until they are needed. In the context of images and videos, the term “non-critical” refers to being off-screen so a user won’t notice them missing without scrolling. Then, every user interaction event – especially screen scrolling – should trigger a recalculation process to determine whether any of the Lazily Loaded resources should begin to load. In shorts, the user scrolls down and image loading starts.
Thanks to this, a browser can focus on loading page content and necessary resources first, shortening the overall time needed to display a requested page, hence improving user experience. Moreover, a shorter page loading time helps increasing search engine rank!
I’m sure you’ve seen this lazy loading image effect work multiple times on both small and large websites. You can find “lazy images” on Google Images, Facebook, Medium, as well as simple, personal pages. Let’s look at this lazy loading example:
Read more: Honey, I shrunk the node_modules! …and improved app’s performance in the process
Implementation of lazy loading
Implementing Lazy Loading is pretty straightforward and comes down to listening to a page scroll and checking whether to load new resources. If you wrote a code that listens to scroll events in the past, you probably already know that besides listening to scroll
event, you should also handle resize
and orientationchange
events. Surprise, surprise – it’s not required anymore! All thanks to built-in IntersectionObserver
that does all the work internally and has better performance in general.
Keep in mind that older browsers don’t support IntersectionObserver
, and you might want to use a polyfill or stick to the old-way implementation with the aforementioned events.
React Component
Note: Lazy Loading in the context of this article is not equal to dynamic imports nor React.lazy()
.
While you could use the plain JavaScript implementation shown below, implementing Lazy Loading on React layer gives you more flexibility, and I recommend using this one.
This code gives you the LazyImage
component that takes src
property equivalent to img
attribute of the same name. At first render, the img
element has src
attribute set to the placeholder inlined URI. When mounting, it’ll begin to observe the rendered img
element until it becomes intersecting.
The important part is to use one IntersectionObserver
globally without creating a new one for each component instance. That’ll help performance and memory usage.
For inspiration and production-ready code, check out `react-lazyload` library.
Implementation of lazy loading in JavaScript
Resource Placeholders
To avoid a situation where resource begins to show up on-screen, but it’s not yet fully loaded, pages often use placeholders to temporarily replace the real content. There’s no single way how to implement them or how they should look. However, the most popular ones are:
Dominant Colour Fill
This simple placeholder technique uses a pre-calculated dominant colour value that’ll fill image or video area until it’s loaded. It requires calculating the colour value on the server-side. This way, a browser doesn’t need to make any additional requests. You can find this method being used on Google Images and Facebook.
Low-Quality Image Placeholders (LQIP)
A step-up in the game of placeholders. As the name suggests, this placeholder is significantly processed and compressed version of an input image. The usual way to go is to scale down images, so the wide side has 16px, and save them in a format that has small enough file headers:
In order to prevent making any additional requests, inline the placeholder image URI.
HTML5 Video Placeholder Image
HTML5 video
tag supports defining poster
attribute that allows displaying a custom image at the time of loading video file. When in pair with preload="none"
attribute, it’ll prevent browsers from downloading any video data before clicking the play button. Make placeholders creative, and they will surely keep users’ attention. 🙂
Benefits of lazy loading
Lazy loading can introduce many benefits, not only for the users but also for website owners too:
- lowers costs of server infrastructure,
- improves loading time,
- makes the overall user experience much better,
- decreases network activity by waiting for the user to have lazily loaded elements in the viewport,
- cuts down hardware resources required to otherwise process additional requests.
To wrap things up, let’s take a look at some new lazy loading developments.
Lazy loading HTML attribute proposal
Chrome 76 introduced a new loading
attribute for img
and iframe
tags that allow lazy loading of the resources without writing any additional JS code. The browser support is very limited, but if you want to learn more, I’ll discuss this feature in my next article about the new native lazy loading for images and iframes in Chromium-based browsers!