Lazy-loading video

image



Usually videos are uploaded using the video tag (although an alternative method using img has appeared , however, its capabilities are limited). The way to implement lazy loading of video depends on its use case. Let's discuss several scenarios, each requiring a different solution.



For videos without automatic autoplay



For videos that are user-initiated (i.e. videos that don't automatically play), you need to specify the appropriate attribute in the video tag :



<video controls preload="none" poster="one-does-not-simply-placeholder.jpg">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>


In the above example uses the attribute preload with a value of none , prohibiting browsers to download any video data. The poster attribute sets the video to a preview image that will take the place of the video on the page until it's loaded. The need for a preview is due to the fact that video loading differs in different browsers:



  • In Chrome, the default value for the preload attribute was auto , but since version 64, the default value is metadata . Even so, on the desktop version of Chrome, a portion of the video can be preloaded using the Content-Range header. Firefox, Edge and Internet Explorer 11 behave similarly.
  • Chrome, Safari 11.0 . 11.2, , Safari iOS .
  • , preload none.


Since the default behavior differs from browser to browser with regard to autoloading, it is probably best to set this behavior explicitly. In cases where the user initiates playback on his own, using preload = "none" is the easiest way to delay video loading on all platforms. The preload attribute isn't the only way to delay the loading of video content. Fast Playback with Video Preload can give you some ideas and insight into working with video playback in JavaScript.



Unfortunately, this is useless if you want to use videos instead of GIFs, we'll talk about that below.



For a video serving as a replacement for an animated GIF



Although animated GIFs are widely used, they fall short of video equivalents in many ways, especially in file size. Animated GIFs can take up several megabytes of data. Videos with similar visual quality are usually much smaller.



Using the video element as a replacement for an animated GIF is not easy. Animated GIFs have three characteristics:



  1. They are automatically played after downloading.
  2. They are continuously looped ( although this is not always the case ).
  3. They have no audio track.


Achieving this with a video tag looks something like this:



<video autoplay muted loop playsinline>
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>


The autoplay , muted, and loop attributes are self-explanatory. playsinline is required for automatic play on iOS . You now have a usable video animation replacement. But how do you add lazy loading to videos? Chrome has no problem with lazy-load video loading , but you can't count on all browsers to provide this optimized behavior. Depending on your audience and application requirements, you may need to take matters into your own hands. First, let's change the video connection:



<video autoplay muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
  <source data-src="one-does-not-simply.webm" type="video/webm">
  <source data-src="one-does-not-simply.mp4" type="video/mp4">
</video>


You may notice the addition of a poster attribute , which allows you to specify a preview image located on the page instead of the video tag until the video is lazy loaded. The video URL is placed in the data-src attribute of each source element .



We use JavaScript to organize "lazy" loading using IntersectionObserver.



document.addEventListener("DOMContentLoaded", function() {
  var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));

  if ("IntersectionObserver" in window) {
    var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(video) {
        if (video.isIntersecting) {
          for (var source in video.target.children) {
            var videoSource = video.target.children[source];
            if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
              videoSource.src = videoSource.dataset.src;
            }
          }

          video.target.load();
          video.target.classList.remove("lazy");
          lazyVideoObserver.unobserve(video.target);
        }
      });
    });

    lazyVideos.forEach(function(lazyVideo) {
      lazyVideoObserver.observe(lazyVideo);
    });
  }
});


We loop through all of the child elements of source and convert their data-src attributes to src attributes . Once you do this, you need to start loading the video by calling the load method , after which the media will start playing automatically in accordance with the autoplay attribute .



By using this method, you get a ready-made video solution that mimics the behavior of an animated GIF, but does not require the same heavy data usage, and you can lazily load this content.



Lazy Loading Libraries



The following libraries can help you with lazy loading videos:



  • lozad.js is an ultra-lightweight version using only Intersection Observer. Thus, it is very efficient, but it will need to be polyfilled before you can use it in older browsers.
  • yall.js is a library that uses Intersection Observer and accesses event handlers. It is compatible with IE11 and major browsers.
  • If you need a lazyload library for React, you might consider react-lazyload . This library does not use Intersection Observer, but provides a way to lazy load images that React developers will be familiar with.


Each of these libraries is documented and contains many markup templates for various lazy loading tasks.



All Articles