有效率的背景處理

網頁功能: content-visibility

當瀏覽器未算繪元件時,請暫停繁重的背景工作,以節省系統資源和電池電力。

總覽

content-visibility: auto 屬性可讓瀏覽器略過檢視區外元素的算繪計算。當瀏覽器決定略過或繼續轉譯元素時,會對該元素觸發 contentvisibilityautostatechange 事件。

監聽這個事件,即可在不需要時暫停耗費資源的操作,例如 <canvas> 動畫、WebGL 轉譯或高頻率 WebSocket 資料輪詢,並在瀏覽器準備顯示內容時及時恢復。

contentvisibilityautostatechange (與 IntersectionObserver比較)

請務必瞭解各 API 的使用時機:

  • 使用 IntersectionObserver 處理應用程式邏輯,該邏輯與可視區域中元素的確切視覺可見度相關 (例如延遲載入資料、無限捲動觸發條件)。
  • 使用 contentvisibilityautostatechange 處理需要大量算繪的工作 (例如複雜的畫布更新或大量 DOM 變動)。這個事件與瀏覽器的內部轉譯生命週期直接相關。瀏覽器通常會在元素實際顯示在畫面上之前,就開始轉譯元素 (預先轉譯邊界)。這個事件會通知您何時發生這種情況,確保內容已準備好顯示。

導入作業

1. 套用 CSS 內容可見度

在大型容器上設定 content-visibility: auto,並提供預留位置大小,避免捲軸跳動。

.heavy-component {
  /* Defer rendering work when off-screen */
  content-visibility: auto;
  
  /* Mandatory: Provide a placeholder size to prevent layouts shifts.
    - 'auto' is optional and enables the browser to remember the actual size
      once rendered. It must be paired with a <length> value to be used for
      the first render.
    - 'none' tells the browser not to apply any intrinsic width to this element.
      It can be used for either the height or the width value.
    - '500px' is the estimated height of this element. This can be any valid
      CSS <length> value. Replace it with the expected height of your
      component.
   */
  contain-intrinsic-size: auto none auto 500px;
}

2. 監聽狀態變更

為 contentvisibilityautostatechange 新增事件監聽器,以便暫停或繼續背景工作。

const component = document.querySelector('.heavy-component');

// Option 1: Direct listener (recommended)
component.addEventListener('contentvisibilityautostatechange', (event) => {
  if (event.skipped) {
    // The browser skipped rendering this content.
    // DO NOT perform heavy mutations or animation loops here.
    stopSimulation();
    pauseWebSocketPolling();
  } else {
    // The browser is about to render the content.
    // Resume your work so it is ready when visible.
    startSimulation();
    resumeWebSocketPolling();
  }
});

// Option 2: Capturing listener for event delegation
document.addEventListener('contentvisibilityautostatechange', (event) => {
  if (event.target.matches('.heavy-component')) {
    if (event.skipped) {
      stopSimulation();
    } else {
      startSimulation();
    }
  }
}, { capture: true });

備用策略

content-visibility 屬性和相關聯的 contentvisibilityautostatechange 事件是漸進增強。在不支援這類 Cookie 的瀏覽器中:

  • 系統會忽略 CSS 屬性,並正常顯示內容。
  • 事件不會觸發,因此背景工作會繼續正常執行,不會進行最佳化。

如果必須支援在舊版瀏覽器上暫停工作,可以改用 IntersectionObserver 做為粗略近似值。這也有助於節省舊裝置的電池和 CPU。

// Fallback using IntersectionObserver for older browsers
const target = document.getElementById('target-container');

// Check if content-visibility is supported
const isSupported = 'contentVisibility' in document.documentElement.style;

if (!isSupported) {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        // The element is close to the screen. Start work!
        startSimulation();
      } else {
        // The element is far away. Pause work!
        stopSimulation();
      }
    });
  }, {
    // Use rootMargin to start rendering before it hits the screen
    rootMargin: '200px'
  });

  observer.observe(target);
}