延遲載入影片

圖片元素相同,您也可以延遲載入影片。影片通常是透過 <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>

上述範例使用值為 nonepreload 屬性,避免瀏覽器預先載入「任何」影片資料。poster 屬性為 <video> 元素提供預留位置,該預留位置會在影片載入時佔用空間。這是因為不同瀏覽器載入影片的預設行為可能不同:

  • 在 Chrome 中,preload 的預設值是 auto,但自 Chrome 64 版本起,其預設值為 metadata。即便如此,在電腦版 Chrome 中,系統可能會使用 Content-Range 標頭預先載入一部分影片。其他以 Chromium 為基礎的瀏覽器和 Firefox 的運作方式很類似。
  • 和電腦版 Chrome 一樣,11.0 電腦版的 Safari 會預先載入一段影片。從 11.2 版開始,系統只會預先載入影片中繼資料。在 iOS 版 Safari 中,系統絕不會預先載入影片
  • 啟用數據節省模式時,preload 預設為 none

由於與 preload 相關的瀏覽器預設行為並非無法變更,因此使用明確性可能是最理想的做法。在這種情況下,當使用者啟動播放作業時,使用 preload="none" 是延遲載入所有平台影片最簡單的方法。preload 屬性並不是延遲影片內容載入的唯一方法。使用影片預先載入的快速播放功能可提供一些想法和深入分析,協助您瞭解如何在 JavaScript 中播放影片。

可惜的是,如果想用影片取代動畫 GIF,則沒辦法派上用場。詳情請見下文。

適合用來取代 GIF 動畫的影片

雖然動畫 GIF 的用途很廣泛,但在許多方面都不如同等影片,特別是在檔案大小方面。GIF 動畫可延伸至數個 MB 的資料。影像品質相似的影片通常比圖像小

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

autoplaymutedloop 屬性都很簡單明瞭。在 iOS 中自動播放功能必須使用 playsinline。現在,您已取得可跨平台使用的影片-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-lazyloadlozad.js 是超輕量的選項,僅使用 Intersection Observer。因此,這類 API 效能相當優異,但需經過多層填入,才能在舊版瀏覽器中使用。
  • yall.js 是使用 Intersection Observer 且會改回使用事件處理常式的程式庫。也可以使用 data-poster 屬性延遲載入影片 poster 圖片。
  • 如果您需要 React 專用的延遲載入程式庫,不妨考慮回應延遲載入。雖然並未使用 Intersection Observer,但它針對那些習慣透過 React 開發應用程式的人員,提供熟悉的延遲載入映像檔

這些延遲載入程式庫都已詳細記載,並為各種延遲載入項目提供許多標記模式。