Elaborazione in background efficiente

Funzionalità web: content-visibility

Metti in pausa le attività in background pesanti quando un componente non viene visualizzato dal browser per risparmiare risorse di sistema e durata della batteria.

Panoramica

La proprietà content-visibility: auto consente al browser di saltare i calcoli di rendering per gli elementi che si trovano molto al di fuori della visualizzazione. Quando il browser decide di saltare o riprendere il rendering di un elemento, attiva l'evento contentvisibilityautostatechange su quell'elemento.

Se ascolti questo evento, puoi mettere in pausa operazioni costose come animazioni <canvas>, rendering WebGL o polling dei dati WebSocket ad alta frequenza quando non sono necessari e riprenderle appena in tempo quando il browser si prepara a visualizzare i contenuti.

contentvisibilityautostatechange rispetto a IntersectionObserver

È importante capire quando utilizzare ciascuna API:

  • Utilizza IntersectionObserver per la logica dell'applicazione legata alla visibilità visiva esatta di un elemento nell'area visibile (ad es. dati di caricamento lento, attivatori di scorrimento continuo).
  • Utilizza contentvisibilityautostatechange per le operazioni di rendering più complesse (come aggiornamenti complessi del canvas o mutazioni DOM pesanti). Questo evento è direttamente collegato al ciclo di vita del rendering interno del browser. Il browser spesso inizia a eseguire il rendering di un elemento prima che venga effettivamente visualizzato sullo schermo (il margine di pre-rendering). Questo evento ti informa quando ciò accade, assicurandoti che i tuoi contenuti siano pronti per essere visualizzati.

Implementazione

1. Applica la proprietà CSS content-visibility

Imposta content-visibility: auto sul contenitore pesante e fornisci una dimensione del segnaposto per evitare che la barra di scorrimento salti.

.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. Ascolta le modifiche dello stato

Aggiungi un listener di eventi per contentvisibilityautostatechange per mettere in pausa o riprendere le attività in background.

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 });

Strategie di riserva

La proprietà content-visibility e l'evento contentvisibilityautostatechange associato sono potenziamenti progressivi. Nei browser che non li supportano:

  • La proprietà CSS viene ignorata e i contenuti vengono visualizzati normalmente.
  • L'evento non viene mai attivato, quindi le attività in background continueranno a essere eseguite normalmente senza ottimizzazione.

Se devi supportare la messa in pausa delle attività su browser meno recenti, puoi utilizzare IntersectionObserver come approssimazione. In questo modo, risparmi batteria e CPU anche sui dispositivi meno recenti.

// 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);
}