视频懒加载技术详解

作者:林语者 分类:工程代码

视频懒加载技术详解

与图片元素类似,视频也可以实现延迟加载。视频通常通过 <video> 元素加载,而对于托管在YouTube等其他服务上的视频,则可能需要使用 <iframe>(在这种情况下,请参阅关于iframe延迟加载的文章)。

<video> 元素的延迟加载方法因存在多种不同解决方案而有所不同,具体取决于您的使用场景。

非自动播放视频场景

通常建议避免视频自动播放,以便用户能够控制视频播放。在这种情况下,最好的方法是在 <video> 元素上指定 preload 属性,以避免浏览器加载整个视频文件。

<video controls preload="none" poster="placeholder.jpg">
  <source src="video.mp4" type="video/mp4">
</video>

在上面的示例中,我们将 preload 属性值设为 none,以防止浏览器预加载任何视频数据。poster 属性为 <video> 元素指定了一个占位图,在视频加载期间占据空间。

大多数浏览器中,preload 默认设置为 metadata,会使用 Content-Range 头部预加载部分视频数据。这可能导致下载的数据量超过实际需要,特别是在浏览器不支持 Content-Range 头部的情况下。即使支持,浏览器也可能无法知道元数据存储在哪些字节中,因为它们可能不在文件开头。因此,我们建议使用 preload="none" 来避免视频预加载。

您还可以使用 onmouseenter 属性(或等效的 mouseenter 事件处理程序)进行扩展,在用户将鼠标悬停在视频上时预加载元数据:

<video controls 
       preload="none" 
       poster="placeholder.jpg"
       onmouseenter="this.preload='metadata'">
  <source src="video.mp4" type="video/mp4">
</video>

这不仅减少了用户播放视频时的延迟,还能立即显示视频时长信息。

视频可能符合LCP候选元素的条件。由于海报图片比视频加载更快,如果视频是LCP候选元素,应使用海报图片,并通过 fetchpriority 属性设置为 "high" 进行预加载。

作为GIF动画替代方案

自动播放视频最常用于实现GIF风格的快速动画。虽然动画GIF被广泛使用,但与视频相比,特别是在文件大小方面存在一些劣势。动画GIF可能会扩展到数MB的数据,而画质相当的视频文件通常要小得多。

使用 <video> 元素替代动画GIF并不像使用 <img> 元素那么简单。动画GIF具有以下三个特征:

  1. 加载后自动播放
  2. 连续循环播放(不一定总是如此)
  3. 没有音轨

<video> 元素中实现这些特性的代码如下:

<video autoplay muted loop playsinline>
  <source src="video.mp4" type="video/mp4">
</video>

autoplaymutedloop 属性的功能如其名称所示。playsinline 在iOS设备上实现自动播放是必需的。这样就获得了一个跨平台工作的视频替代GIF的方案。那么如何实现延迟加载呢?

首先,根据需要修改标记:

<video autoplay muted loop playsinline poster="placeholder.jpg" class="lazy">
  <source data-src="video.mp4" type="video/mp4">
</video>

我们添加了 poster 属性,该属性允许指定一个占位图,在视频延迟加载期间占据 <video> 元素的空间。与延迟加载示例类似,我们将视频URL存储在每个 <source> 元素的 data-src 属性中。

接下来,使用基于Intersection Observer的图像懒加载示例类似的JavaScript代码:

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 =<span class="highlight"> "string" && videoSource.tagName </span>= "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);
    });
  }
});

延迟加载 <video> 元素时,需要遍历所有子 <source> 元素,将其 data-src 属性更改为 src 属性。然后调用元素的 load 方法触发视频加载,此时媒体将根据 autoplay 属性自动开始播放。

这种方法提供了模拟GIF动画行为的视频解决方案,同时不会产生动画GIF那样的大量数据使用,并且可以对内容进行延迟加载。

懒加载库推荐

以下库可以帮助您实现视频延迟加载:

  • vanilla-lazyloadlozad.js 是非常轻量的选项,仅使用Intersection Observer。因此性能非常出色,但在旧版浏览器中需要使用polyfill
  • yall.js 是一个使用Intersection Observer并具有事件处理程序回退的库。还可以使用 data-poster 属性延迟加载视频的海报图像
  • 如果需要React特定的延迟加载库,可以考虑 react-lazyload。它不使用Intersection Observer,但为React应用程序开发人员提供了熟悉的图像延迟加载方法

这些延迟加载库都有详细的文档,提供了丰富的标记模式来应对各种延迟加载场景。

评论

发表评论

正在加载评论...