發布日期:2019 年 8 月 16 日
如同圖片元素,您可能也想使用延遲載入影片。影片通常會透過 <video>
元素載入,但如果是託管於 YouTube 等其他服務的影片,則可能會使用 <iframe>
(如果是這種情況,請參閱延遲載入 iframe 一文)。
<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>
上一個範例使用 preload
屬性,其值為 none
,可防止瀏覽器預先載入任何影片資料。poster
屬性會為 <video>
元素提供預留位置,在影片載入期間佔用該空間。
在大多數瀏覽器中,preload
預設為 metadata
,並使用 Content-Range
標頭預先載入部分影片。這可能會導致下載的資料量超出預期,尤其是在瀏覽器不支援 Content-Range
標頭的情況下。即使瀏覽器支援這項功能,也無法得知中繼資料儲存在哪個位元組,而且可能不會儲存在檔案開頭。因此,如要避免載入影片,請務必指定 none
並使用 preload="none"
。
這項功能還可進一步強化,在使用者將游標懸停在影片上時,透過 onmouseenter
屬性 (或等同的 mouseenter
事件處理常式) 預先載入中繼資料:
<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 候選條件。poster
圖片的載入速度比影片快,因此如果要將其設為 LCP 候選項目,建議您使用海報圖片,並預先載入,fetchpriority
屬性值為 "high"
:
<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>
影片用於取代 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。因此,這些元素的效能極佳,但必須先進行多重填充,才能在舊版瀏覽器中使用。
- yall.js 是使用 Intersection Observer 的程式庫,並會改用事件處理常式。也可以使用
data-poster
屬性,以延遲載入方式載入影片poster
圖片。 - 如果您需要 React 專用的延後載入程式庫,不妨考慮使用 react-lazyload。雖然它不會使用 Intersection Observer,但確實為習慣使用 React 開發應用程式的人,提供圖片延後載入的熟悉方法。
每個延遲載入程式庫都提供完善的文件,其中包含許多標記模式,可用於各種延遲載入作業。