Native lazy-loading - Why doesn’t the video element have it?

Lazy-loading is a strategy to identify resources that are not critical for the initial page load, and load them only when needed. It’s a way to reduce page load times. We have the ability to lazy-load images and iframes in browsers via the loading attribute.

HTML
<img src="cat.jpg" loading="lazy" alt="felix the cat" >
<iframe src="a4sefRp.html" loading="lazy" title="dancing cat animation"></iframe>

It just made me wonder why the video element has been overlooked. Is it because most videos live on YouTube now and are embedded on websites via iframes?

What led me to ask this question?

When writing an article recently, I had a short screen recording to demo some functionality. I wanted to include it as autoplaying video, similar to where you might use an animated GIF. That’s when I realised there is no native lazy loading for videos.

This nudged me towards converting the video into an animated WebP instead because I can lazy load it. I did not want to go on a tangent to research what people do with videos more at the time, but today I will!

How to lazy load videos - there is no single method

They are 2 distinct use cases for lazy loading videos that are handled differently. Let’s take a look at these to understand the topic better.

Use Case 1: Videos where playback is initiated by the user

This use case is where have controls on the video, and it up the user to play the video.

You can specify the preload attribute on the video element to control loading. By providing preload="none", the browser should be prevented from loading the video data.

HTML
<!-- disable preloading -->
<video controls preload="none" width="300" poster="img/cover.jpg">
<source src="files/sample.mp4" type="video/mp4">
</video>

On some browsers, the video will be have no background. You can make it look better by using the poster attribute to provide a preview image.

When the user clicks the play button of the video, then the video will be loaded.

Use Case 2: A video acting as an animated GIF replacement

This was my use case. For a README or technical articles, it is common to include a demo of functionality with an autoplaying video.

In this use case, preload="none" will not work. Typically, when you have the autoplay attribute to play a video automatically, the browser will load the video! So if you use both together, most browsers will disregard preload="none". So, it is up to us to write some JavaScript to tell the browser when to load the video.

You can use a lazy loading library such as vanilla-lazyload, or you can write your own JavaScript code. To write your own code is quite short. Let’s give it a go to see what it is like.

First let’s prepare the HTML. To not load the videos, we will exclude the src attribute on the source elements that point to the video files. Instead we will stash the URL of the videos in the data-src attribute. And lastly, we will add a “lazy” class to video to identiy it as a lazy loading participant.

HTML
<video class="lazy" autoplay muted loop playsinline width="600" height="300" poster="cover.jpg">
<source data-src="screen-recording.webm" type="video/webm">
<source data-src="screen-recording.mp4" type="video/mp4">
</video>

Onto the JavaScript code. We will use the IntersectionObserver API to detect when the video element with the “lazy” class comes into view, and will add a src attribute to each source element and copy the URL from the data-src to it. It takes about 30 lines of JavaScript to pull this off.

Here is the codepen:

You can check in the Network tab in the browser devtools to see it working as you scroll towards the video.

This code does not cover the case where you have the src attribute in video by the way! You can adapt it yourself if you want to use it in that way.

Conclusion

For user-initiated playing of videos, the preload attribute can prevent the loading of a video and we can provide a “preview” placeholder with a poster image. When it comes to lazy loading autoplaying videos we are left short. In about 30 lines of JavaScript, you can add this behaviour yourself with the IntersectionObserver API. It would be nice to have a native version of this. Browser vendors could add a new value for preload; or could add the same behaviour of the loading attribute as they have for img.

Where is the suggestion box? 😄📥

Tagged