与图片元素一样,您还可以延迟加载视频。视频通常使用 <video>
元素加载(不过,使用 <img>
的替代方法的实现方式有限。不过,延迟加载 <video>
的方法取决于用例。我们来讨论几种场景,每种场景都需要不同的解决方案。
对于不会自动播放的视频
对于由用户启动播放的视频(即不自动播放的视频),可能需要在 <video>
元素中指定 preload
属性:
<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>
上面的示例使用值为 none
的 preload
属性,以防止浏览器预加载任何视频数据。poster
属性为 <video>
元素提供一个占位符,该占位符将在视频加载时占据空间。这是因为,视频加载的默认行为可能因浏览器而异:
- 在 Chrome 中,
preload
的默认值之前为auto
,但从 Chrome 64 开始,默认值为metadata
。即便如此,在桌面版 Chrome 上,系统可能会使用Content-Range
标头预加载视频的部分内容。其他基于 Chromium 的浏览器和 Firefox 的行为方式类似。 - 与桌面版 Chrome 一样,Safari 11.0 桌面版会预加载一系列视频。 从 11.2 版开始,系统仅会预加载视频元数据。在 iOS 版 Safari 中,系统从不预加载视频。
- 启用流量节省程序模式后,
preload
默认为none
。
由于浏览器在 preload
方面的默认行为并非一成不变,因此最好选择明确设置。在这种情况下,当用户启动播放时,使用 preload="none"
是延迟加载所有平台上视频的最简单方法。preload
属性不是延迟加载视频内容的唯一方式。利用视频预加载快速播放可为您提供有关使用 JavaScript 播放视频的一些想法和见解。
遗憾的是,当您想要使用视频代替动画 GIF(稍后将进行介绍)时,事实证明此方法并不实用。
用于替换动画 GIF
虽然动画 GIF 应用广泛,但其在很多方面都不如视频,尤其是在文件大小方面。GIF 动画的数据大小可达数 MB而画质相当的视频往往小得多
使用 <video>
元素代替动画 GIF 并不像使用 <img>
元素那么简单。动画 GIF 具有三个特征:
- 视频加载后会自动播放。
- 它们会不断循环(但并非总是如此)。
- 没有音轨。
使用 <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>
autoplay
、muted
和 loop
属性均一目了然,无需另作说明。playsinline
是 iOS 中自动播放所必需的。现在,您已经有了可以跨平台使用的“视频即 GIF”替代品。但如何实现延迟加载呢?首先,请相应地修改 <video>
标记:
<video class="lazy" 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>
您会发现添加了 poster
属性,该属性可让您指定占位符,以占用 <video>
元素的空间,直到视频延迟加载。与 <img>
延迟加载示例一样,将视频网址存储在每个 <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 === "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);
});
}
});
延迟加载 <video>
元素时,您需要遍历所有 <source>
子元素,并将其 data-src
属性转换为 src
属性。完成此操作后,您需要通过调用该元素的 load
方法来触发视频加载,然后媒体将按照 autoplay
属性自动播放。
使用此方法,您可以获得模拟动画 GIF 行为的视频解决方案,该解决方案不会像动画 GIF 那样产生大量流量消耗,并且您可以延迟加载相应内容。
延迟加载库
以下库可以帮助您延迟加载视频:
- vanilla-lazyload 和 lozad.js 是超轻量级选项,仅使用 Intersection Observer。因此,它们的性能极佳,但需要先 polyfill 才能在旧版浏览器上使用。
- yall.js 是一个使用 Intersection Observer 并回退到事件处理脚本的库。它还可以使用
data-poster
属性延迟加载视频poster
图片。 - 如果您需要 React 专用的延迟加载库,不妨考虑使用 react-lazyload。虽然它不使用 Intersection Observer,但它为习惯于使用 React 开发应用的用户提供熟悉的图片延迟加载方法。
其中每个延迟加载库都有完备的说明文档,并提供了大量适用于各种延迟加载工作的标记模式。