延遲載入圖片

由於圖片是以 <img> 元素或 CSS 背景圖片的形式內嵌在 HTML 中,因此可顯示在網頁中。本文將說明如何延遲載入這兩種圖片。

內嵌圖片

最常見的延遲載入候選圖片是用於 <img> 元素的圖片。使用內嵌圖片時,我們有三種延遲載入選項,這些選項可以搭配使用,以達到最佳瀏覽器相容性:

使用瀏覽器層級的延遲載入

Chrome 和 Firefox 都支援使用 loading 屬性延遲載入功能。這項屬性可以新增至 <img> 元素和 <iframe> 元素中。lazy 值會指示瀏覽器立即載入可視區域中的圖片,並在使用者捲動靠近圖片時擷取其他圖片。

如要進一步瞭解瀏覽器支援,請參閱 MDN 瀏覽器相容性表格的 loading 欄位。如果瀏覽器不支援延遲載入,系統會忽略該屬性,並照常立即載入圖片。

對大多數網站來說,在內嵌圖片中加入這項屬性有助於提升效能,並可以儲存使用者載入絕不會捲動的圖片。如果您擁有大量圖片,並想確保瀏覽器使用者不支援延遲載入功能,就需要將其搭配接下來說明的其中一種方法結合使用。

詳情請參閱網頁版瀏覽器層級的延遲載入功能

使用 Intersection Observer

為了對 <img> 元素進行 polyfill 延遲載入,我們會使用 JavaScript 來檢查這些元素是否位於可視區域。如果是,這些屬性的 src (有時還有 srcset) 屬性會填入所需圖片內容的網址。

如果您之前曾編寫延遲載入程式碼,可以使用 scrollresize 等事件處理常式來完成工作。雖然這個方法在所有瀏覽器上是最相容的方式,但新式瀏覽器可讓您透過 Intersection Observer API 以更高效且有效率的方式檢查元素瀏覽權限。

Intersection Observer 比依賴各種事件處理常式的程式碼更容易使用及讀取,因為您只需要註冊觀察器來監控元素,而不必編寫繁瑣的元素瀏覽權限偵測程式碼。接下來,您只需要決定元素顯示時的處理方式。舉例來說,以下是延遲載入的 <img> 元素的基本標記模式:

<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">

這項標記有三個相關部分,請著重在:

  1. class 屬性,這是您在 JavaScript 中選取的元素。
  2. src 屬性,會參照網頁首次載入時顯示的預留位置圖片。
  3. data-srcdata-srcset 屬性是預留位置屬性,其中包含您將在元素移至可視區域後載入的圖片網址。

現在讓我們看看如何在 JavaScript 中使用 Intersection Observer,利用以下標記模式延遲載入圖片:

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to event handlers here
  }
});

在文件的 DOMContentLoaded 事件中,這個指令碼會查詢 DOM,找出類別為 lazy 的所有 <img> 元素。如果 Intersection Observer 可用,請建立新的觀察器,以便在 img.lazy 元素進入可視區域時執行回呼。

Intersection Observer 適用於所有新式瀏覽器。因此,將此函式做為 loading="lazy" 的 polyfill 可確保大多數訪客可以使用延遲載入。

CSS 中的圖片

雖然 <img> 標記是在網頁中使用圖片最常見的方式,但您也可以透過 CSS background-image 屬性 (和其他屬性) 叫用圖片。瀏覽器層級延遲載入不適用於 CSS 背景圖片,因此如果您有可延遲載入的背景圖片,就需要考慮其他方法。

無論 <img> 元素是否可見,CSS 中的圖片載入行為都是透過更多推測結果完成,建構文件和 CSS 物件模型算繪樹狀結構時,瀏覽器會先檢查 CSS 如何套用至文件,然後再要求外部資源。如果瀏覽器判定涉及外部資源的 CSS 規則,並不適用於文件目前建構的文件,則瀏覽器不會提出要求。

此推測行為可利用 JavaScript 判斷元素是否位於可視區域內,然後為該元素套用樣式叫用背景圖片的類別,藉此延遲在 CSS 中載入圖片。如此一來,系統會在需要時下載圖片,而非在初始載入時下載。舉例來說,假設某個元素包含大型主頁橫幅背景圖片:

<div class="lazy-background">
  <h1>Here's a hero heading to get your attention!</h1>
  <p>Here's hero copy to convince you to buy a thing!</p>
  <a href="/buy-a-thing">Buy a thing!</a>
</div>

div.lazy-background 元素通常會包含部分 CSS 叫用的主頁橫幅。在此延遲載入範例中,您可以透過在可視區域加入元素的 visible 類別,隔離 div.lazy-background 元素的 background-image 屬性:

.lazy-background {
  background-image: url("hero-placeholder.jpg"); /* Placeholder image */
}

.lazy-background.visible {
  background-image: url("hero.jpg"); /* The final image */
}

接著,使用 JavaScript 檢查元素是否位於可視區域 (透過 Intersection Observer!),並在當時將 visible 類別新增至 div.lazy-background 元素,在該時間點載入圖片:

document.addEventListener("DOMContentLoaded", function() {
  var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));

  if ("IntersectionObserver" in window) {
    let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          entry.target.classList.add("visible");
          lazyBackgroundObserver.unobserve(entry.target);
        }
      });
    });

    lazyBackgrounds.forEach(function(lazyBackground) {
      lazyBackgroundObserver.observe(lazyBackground);
    });
  }
});

對 Largest Contentful Paint (LCP) 的影響

延遲載入是一項絕佳的最佳化功能,可將圖片載入至實際需要的時間,減少啟動期間的整體數據用量和網路爭用情況。這樣可以縮短啟動時間,並減少圖片解碼所需時間,進而減少主執行緒的處理速度。

不過,如果您偏好使用延遲載入技術,則可能對網站的最大內容繪製 LCP 造成負面影響。建議您避免在啟動期間延遲載入可視區域內的圖片。

使用以 JavaScript 為基礎的延遲載入器時,建議您避免延遲載入可視區域圖片,因為這些解決方案通常會使用 data-srcdata-srcset 屬性做為 srcsrcset 屬性的預留位置。但問題在於瀏覽器預先載入掃描器在啟動期間找不到這些圖片,因而延遲載入這些圖片。

即使是使用瀏覽器層級的延遲載入來延遲載入可視區域圖片,也還是有辦法回溯觸發。將 loading="lazy" 套用至可視區域圖片時,該圖片會延遲顯示,直到瀏覽器確定圖片位於可視區域內,而這可能會影響網頁的 LCP。

不要在啟動期間延遲載入可視區域中顯示的圖片。這是一種模式,會對網站的 LCP 造成負面影響,進而影響使用者體驗。如需在啟動時盡快載入圖片,請不要延遲載入,讓圖片盡快載入!

延遲載入程式庫

建議您盡可能使用瀏覽器層級的延遲載入功能,但如果您後來發現無法繼續使用舊版瀏覽器 (例如大量使用舊版瀏覽器的使用者),可以使用下列程式庫延遲載入圖片:

  • lazysizes 是功能完整的延遲載入程式庫,可延遲載入圖片和 iframe。這個模式使用的模式與此處顯示的程式碼範例類似,程式碼會自動繫結至 <img> 元素的 lazyload 類別,且會要求您在 data-src 和/或 data-srcset 屬性中指定圖片網址,其中的內容會分別切換至 src 和/或 srcset 屬性。它使用 Intersection Observer (可以 polyfill),且可藉由多種外掛程式擴充,執行延遲載入影片等作業。進一步瞭解如何使用延遲尺寸
  • vanilla-lazyload 是延遲載入圖片、背景圖片、影片、iframe 和指令碼的輕量選項。這個 API 利用 Intersection Observer,支援回應式圖片,並支援瀏覽器層級的延遲載入。
  • lozad.js 是另一個僅使用 Intersection Observer 的輕量選項。因此,它的效能非常高,但需要先填充,才能在舊版瀏覽器上使用。
  • 如果您需要 React 專屬的延遲載入程式庫,請考慮React-lazyload。雖然不使用 Intersection Observer,但「確實」提供了一種熟悉的延遲載入映像檔方法,適合習慣使用 React 開發應用程式的人。