延迟加载视频

发布时间:2019 年 8 月 16 日,上次更新时间:2026 年 7 月 2 日

图片元素一样,您可能也希望延迟加载视频。视频通常使用 <video> 元素加载,但对于托管在其他服务(例如 YouTube)上的视频,它们可能会使用 <iframe>s(在这种情况下,请查看 延迟加载 iframe 中的文章)。

如何延迟加载 <video> 取决于用例,因为有几种不同的解决方案。

使用 loading 属性

浏览器已开始支持媒体元素(<video><audio>)上的 loading 属性。如果支持此属性,则表示只需添加 loading="lazy" 属性,媒体和任何海报图片都会自动延迟加载:

<video controls loading="lazy" 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>

使用 loading="lazy" 将阻止 poster 图片加载,直到进入或靠近视口,然后使用 preload 属性来决定加载多少 video。这也意味着 autoplay 视频在进入或靠近视口之前不会自动播放。The loading="lazy" 属性适用于 posterpreloadautoplay 属性,并不会取代对这些属性的需求。

不支持媒体元素上的 loading 属性的浏览器会忽略此属性,这会导致 poster 图片立即加载,而视频则根据 preload 属性加载,我们将在下一部分介绍该属性。

使用 preload 属性延迟加载不会自动播放的视频

避免自动播放视频通常是最佳实践,因为这样可以将控制权交给用户。在这些情况下,在 <video> 元素上指定 preload 属性 是避免在需要之前加载整个视频的最佳方式:

<video controls loading="lazy" 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>

上一个示例使用值为 nonepreload 属性来阻止浏览器预加载任何视频数据,即使在视口中也是如此。 poster 属性为 <video> 元素提供了一个占位符,该占位符会在视频加载时占据空间。

在大多数浏览器中,preload 默认为 metadata,并且使用 Content-Range 标头预加载部分视频。这可能会导致下载的数据超出预期,因为浏览器无法知道元数据存储在哪些字节中,并且元数据可能不会存储在文件的开头。因此,避免加载视频的最佳方法是使用 preload="none"

您可以使用 onmouseenter 属性(或等效的 mouseenter 事件处理程序)在用户将鼠标悬停在视频上时预加载元数据,从而进一步增强此功能:

<video controls
  loading="lazy"
  preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

这不仅减少了用户播放视频时的延迟,还会在用户将鼠标悬停在视频上时立即显示视频的时长。

视频可以作为 LCP 候选元素poster 图片的加载速度比视频快,因此如果它是 LCP 候选元素,您应该使用海报图片,但也要预加载该图片,并使用 fetchpriority 属性值 "high",因为在撰写本文时,您无法为海报属性指定 fetchpriority

<link rel="preload" href="one-does-not-simply-placeholder.jpg" as="image" fetchpriority="high">
<video controls preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

作为 LCP 元素的视频不应使用 loading="lazy",就像 您不应延迟加载 LCP 图片一样。 视频。

对于用作动画 GIF 替代品的视频

自动播放视频通常用于 GIF 样式的快速动画。虽然动画 GIF 得到广泛使用,但在许多方面,尤其是文件大小方面,它们不如视频等效项。动画 GIF 的大小可能达到几兆字节的数据。视觉质量相似的视频往往要小得多。

使用 <video> 元素作为动画 GIF 的替代品不像 <img> 元素那样简单。动画 GIF 具有三个特点:

  1. 加载后自动播放。
  2. 持续循环播放(但情况并非总是如此)。
  3. 没有音轨。

使用 <video> 元素实现此目的的方式如下所示:

<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>

loading="lazy" 属性可避免在靠近视口之前加载视频。autoplaymutedloop 属性不言自明。在 iOS 中,必须使用 playsinline 才能自动播放

现在,您有了一个可在各个平台上使用的视频作为 GIF 替代品。但如何延迟加载它呢?

对于支持此属性的浏览器,loading="lazy" 是最简单的选项:

<video loading="lazy" 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>

如需在其他浏览器中支持视频的延迟加载,您需要使用 JavaScript 并相应地修改 <video> 标记:

<video class="lazy" preload="none" controls muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

您会注意到 autoplay 已被移除,并且添加了 class="lazy"preload="none"poster 属性,这些属性可让您指定一个占位符,在视频延迟加载之前占据 <video> 元素的空间。然后,我们使用 JavaScript Intersection Observer 重新启用自动播放:

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) {
          video.target.removeAttribute('preload');
          video.target.removeAttribute('controls');
          video.target.autoplay = true;
          video.target.classList.remove("lazy");
          lazyVideoObserver.unobserve(video.target);
        }
      });
    });

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

使用此方法,视频默认不会自动播放,只有当 Intersection Observer 检测到视频进入视口时才会自动播放。此外,controls 属性会处理 JavaScript 失败的情况。总而言之,这意味着您拥有一个模拟动画 GIF 行为的视频解决方案,但不会像动画 GIF 那样产生大量数据使用,并且您可以延迟加载该内容。

延迟加载库

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

  • vanilla-lazyloadlozad.js 是仅使用 Intersection Observer 的超轻量级选项。因此,它们的性能非常高,但您需要在旧版浏览器上使用它们之前对其进行 polyfill。
  • 如果您需要特定于 React 的延迟加载库,可以考虑使用 react-lazyload。虽然它不使用 Intersection Observer,但它确实为习惯使用 React 开发应用的用户提供了一种熟悉的延迟加载图片的方法。

每个延迟加载库都有详细的文档,其中包含大量标记模式,可用于各种延迟加载工作。

随着更多浏览器支持 <video>loading 属性,我们预计 JavaScript 解决方案(包括库)的使用量会减少,而内置解决方案的使用量会增加,除非用户希望获得比内置解决方案更多的控制权。