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