Pausieren Sie rechenintensive Hintergrundaufgaben, wenn eine Komponente nicht vom Browser gerendert wird, um Systemressourcen und Akkulaufzeit zu sparen.
Übersicht
Mit der Property content-visibility: auto kann der Browser Rendering-Berechnungen für Elemente überspringen, die sich weit außerhalb des Darstellungsbereichs befinden. Wenn der Browser das Rendern eines Elements überspringt oder fortsetzt, wird das Ereignis contentvisibilityautostatechange für dieses Element ausgelöst.
Wenn Sie auf dieses Ereignis warten, können Sie ressourcenintensive Vorgänge wie <canvas>-Animationen, WebGL-Rendering oder hochfrequente WebSocket-Datenabfragen pausieren, wenn sie nicht benötigt werden, und sie rechtzeitig fortsetzen, wenn der Browser die Anzeige des Inhalts vorbereitet.
contentvisibilityautostatechange gegen IntersectionObserver
Es ist wichtig zu wissen, wann welche API verwendet werden sollte:
- Verwenden Sie
IntersectionObserverfür die Anwendungslogik, die an die genaue visuelle Sichtbarkeit eines Elements im Darstellungsbereich gebunden ist (z.B. Lazy Loading von Daten, Trigger für unendliches Scrollen). - Verwenden Sie
contentvisibilityautostatechangefür rechenintensive Rendering-Aufgaben (z. B. komplexe Canvas-Updates oder umfangreiche DOM-Mutationen). Dieses Ereignis ist direkt mit dem internen Rendering-Lebenszyklus des Browsers verknüpft. Der Browser beginnt oft mit dem Rendern eines Elements, bevor es tatsächlich auf dem Bildschirm angezeigt wird (Pre-Rendering-Rand). Dieses Ereignis gibt an, wann das der Fall ist, damit Ihre Inhalte bereit sind, angesehen zu werden.
Implementierung
1. CSS-Inhaltssichtbarkeit anwenden
Legen Sie content-visibility: auto für den schweren Container fest und geben Sie eine Platzhaltergröße an, um ein Springen der Scrollleiste zu verhindern.
.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. Auf Statusänderungen achten
Fügen Sie einen Event-Listener für contentvisibilityautostatechange hinzu, um Hintergrundaufgaben zu pausieren oder fortzusetzen.
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 });
Fallback-Strategien
Das Attribut content-visibility und das zugehörige Ereignis contentvisibilityautostatechange sind progressive Verbesserungen. In Browsern, die sie nicht unterstützen:
- Die CSS-Eigenschaft wird ignoriert und der Inhalt wird normal gerendert.
- Das Ereignis wird nie ausgelöst, sodass Hintergrundaufgaben wie gewohnt ohne Optimierung ausgeführt werden.
Wenn Sie das Pausieren von Aufgaben in älteren Browsern unterstützen müssen, können Sie als grobe Annäherung auf IntersectionObserver zurückgreifen. Das hilft auch, den Akku und die CPU auf älteren Geräten zu schonen.
// 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);
}