Don’t Load it till it’s Needed

The average web page has nearly doubled in size since 2010. While this might not come as a surprise to any of us, there is certainly plenty that we can do to scale back the weight of our web pages.

One of my favourite ways to prevent page bloat is to treat everything as a resource that doesn’t need to be on the page until the user has to interact with it. The technique is called lazy-loading, and can be performed on almost any asset. It’s especially good for responsive websites, when the same content needs to be loaded across multiple devices, while still loading as quickly as possible. Let’s take a look at a few ways to make this possible.


Images, Video, and Audio

The key to lazy-loading these assets is to leave the html structure in tact, while deferring their src attributes until absolutely necessary.

Images

Let’s take a regular image that hasn’t been adjusted for lazy-loading.

<img src="myimg.png" alt="a picture of bacon or something">

In order to lazy-load this image, the first thing we need to do is address the src attribute, so that the DOM won’t grab the asset immediately. To do that, we’ll change the src attribute into a data attribute. <img data-src="myimg.png" alt="a picture of bacon or something">. If we need to lazy-load a responsive image, our snippet will end up looking something like this: <img data-src="myimg.png" dta-srcset="img1.png 320w, img2.png 640w, img3.png 1280w" data-sizes="(min-width: 33em) 75vw, 100vw" alt="a picture of bacon or something">. One thing to note is that while the sizes attribute is not responsible for loading images, it still needs to be lazy-loaded with the src and srcset attributes. This is because if the sizes attribute is present before any of the image assets, the browser will not load the correct image. A side effect of using this technique is that images won’t initially have a width or height, unless they are set beforehand using css or width and height attributes in the HTML.

Videos

Lazy-loading video assets can be a little bit tricky. While my initial approach was to do something like this – <video data-src="videofile.mp4"</video> – I found that when the src attribute is added, the video won’t function correctly in all browsers. In order to fix this, a slightly more difficult solution is needed. What does end up working is adding <source> tags in between the opening <video> tags as soon as the video is needed.

Audio

Lazy-loading an audio resource is much more like an image, in that all that is needed is to change a data attribute into a source attribute when the resource is needed. Don’t forget to ensure that the controls attribute is present in the audio tag, or else nothing will show up when the tag is present on the page. Here is an example.


Third Party Resources

Every now and then a third party widget needs to be present on a page. These can be things like photo galleries, social networking feeds, comment systems, and ads. Resources like these can often add to initial page load time, with extra requests and heavy files needed to render the widget. In order to prevent widgets from slowing down the site, we’ll want to lazy-load them in whenever possible. This usually means wrapping the entire widget inside of a script tag, and dropping its contents inside of an empty container just before the asset is needed.


Tying it all together

Now that we’ve gone over a few use cases for lazy-loading, let’s take a look at how we can use javascript to tell us when an element needs to be ready and visible to the user.

To do this we’ll be using the getBoundingClientRect() method, which will return an elements size and position relative to the viewport. We’ll attach this to a scroll event listener so that when the user is scrolling we can fire an event to tell us that the element is visible in the viewport. It’s important to remember not to run too many calculations inside of a scroll event listener, since this will lead to performance bottlenecks.

For this demonstration, we’ll be loading an image when it is visible in the users viewport.

See the Pen Lazy-loading an image by Tim (@tevko) on CodePen.

The PolyFill is being included in order to provide support for custom events in IE. We’re also using requestAnimationFrame() which will help to keep a high frame rate while we scroll, allowing for a smooth scrolling experience.

Once the custom event has fired, the notCalled variable is set to false, preventing the checkViewport function from being called needlessly.


Conclusion

While you now have a few techniques aimed at making your websites lighter, faster, and all around easier to use, remember that performance is a constant battle, and there are several other ways to make your site perform better for all devices.


Resources
CustomEvent API
requestAnimationFrame API

Want to become a better web developer?

Join over 25,000 other developer & designers who get awesome links to the best news and articles each week delivered directly to their inbox.

Tim Evko

I'm a front end web developer from New York, with a passion for responsive web development, Sass, and JavaScript. I live on coffee, CodePen demos and flannel shirts. I can also be found on Twitter - @tevko.

3 Comments

  1. Nice straightforward explanation of lazy loading assets. Only issue with this approach is that we have to rely on JavaScript — what if JSON isn’t available? None of our lazy-loaded assets will render — so a user with no JS gets no images, no video, no audio = not the greatest user experience. Not sure there is a way around that — maybe ?

    • Edit: Not JSON — JS. Either comment auto-format or iPad auto-correct.

  2. Great and simple article on lazy load.

This post currently has 3 responses. What do you think?

You can use basic HTML when posting code, please turn all < characters into &lt; or > into &gt;
If the code is multi-line, use <pre><code></code></pre>

Leave a Reply

Your email address will not be published. Required fields are marked *