發布日期: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影片不會自動播放,直到進入或靠近可視區域為止。loading="lazy" 屬性可與 poster、preload 和 autoplay 屬性搭配使用,但不會取代這些屬性。
不支援媒體元素 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>
上例使用 preload 屬性,並將值設為 none,防止瀏覽器預先載入任何影片資料,即使影片位於可視區內也一樣。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 在許多方面都較為遜色,尤其是檔案大小。動畫 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>
loading="lazy" 屬性可避免載入影片,直到影片接近可視區域為止。autoplay、muted 和 loop 屬性不言自明。playsinline 是 iOS 自動播放功能運作的必要條件。
現在您已擁有可跨平台使用的影片,可取代 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);
});
}
});
使用這種方法時,影片不會預設自動播放,只有在交集觀察器偵測到影片進入可視區域時才會播放。此外,controls 屬性會處理 JavaScript 失敗的情況。這表示您擁有可模擬 GIF 動畫行為的影片解決方案,但不會像 GIF 動畫一樣耗用大量資料,而且您可以延遲載入該內容。
延遲載入程式庫
下列程式庫可協助您延遲載入影片:
- vanilla-lazyload 和 lozad.js 是超輕量的選項,只會使用 Intersection Observer。因此效能極佳,但必須先進行 Polyfill,才能在舊版瀏覽器上使用。
- 如需 React 專用的延遲載入程式庫,不妨考慮使用 react-lazyload。雖然它不會使用 Intersection Observer,但會為習慣使用 React 開發應用程式的開發人員,提供熟悉的圖片延遲載入方法。
這些延遲載入程式庫都有詳細說明文件,並提供各種延遲載入作業適用的標記模式。
隨著越來越多瀏覽器支援 <video> 的 loading 屬性,我們預期使用者會減少使用 JavaScript 解決方案 (包括程式庫),改用內建解決方案,除非他們希望取得更多控制權。