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.
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.
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.
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? 😄📥