7 November, 2019
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 them at page load, they are being loaded when needed (that’s why some people call it “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 in your projects.
Browsers try their best to optimise loading pipeline by analysing DOM tree and determine what can they skip while doing the initial render. They use various techniques to achieve that – for example by ignoring elements that have
Note: If you’re looking for the new Lazy Loading HTML
loading attribute for
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”! 😁
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 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.
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 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.
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 effect work multiple times on both small and large websites. You can find it on Google Images, Facebook, Medium, as well as simple, personal pages.
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
orientationchangeevents. 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.
Note: Lazy Loading in the context of this article is not equal to dynamic imports nor
This code gives you the
LazyImage component that takes
src property equivalent to
img attribute of the same name. At first render, the
srcattribute 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.
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
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.
Lazy loading HTML attribute proposal
Chrome 76 introduced a new
loading attribute for
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!