Приостанавливайте тяжелые фоновые задачи, когда компонент не рендерится браузером, для экономии системных ресурсов и заряда аккумулятора.
Свойство content-visibility: auto позволяет браузеру пропускать вычисления, связанные с рендерингом, для элементов, которые находятся далеко за пределами области просмотра. Когда браузер решает пропустить или продолжить рендеринг элемента, он вызывает событие contentvisibilityautostatechange на элементе.
Путем обработки этого события можно приостанавливать дорогие операции, такие как анимации <canvas>, рендеринг WebGL или частые запросы данных через веб-сокеты, когда они не нужны, и возобновлять их, когда браузер готов к отображению контента.
Важно понимать, когда какой API использовать:
- Используйте
IntersectionObserverдля логики приложения, привязанной к точному визуальному состоянию элемента в области просмотра (например, ленивая загрузка данных, триггеры бесконечной прокрутки). - Используйте
contentvisibilityautostatechangeдля тяжелого рендеринга (такого как сложные обновления холста или тяжелые мутации DOM).Это событие привязано прямо к внутреннему циклу рендеринга браузера. Браузер часто начинает рендерить элемент перед его фактическим появлением на экране (отступ предварительного рендеринга (pre-render margin)). Это событие сообщает нам, когда это происходит, гарантируя, что контент готов к отображению.
Установите content-visibility: auto на тяжелом контейнере и предоставьте заполнитель (placeholder) размера для предотвращения прыжков полосы прокрутки.
.heavy-component {
/* Откладываем рендеринг элемента, находящегося за пределами экрана */
content-visibility: auto;
/* Предоставляем заполнитель размера для предотвращения сдвигов макета.
- 'auto' является опциональным и позволяет браузеру запомнить реальный размер элемента
после рендеринга. Он должен использоваться вместе со значением <length> для
первого рендеринга.
- 'none' указывает браузеру не применять внутреннюю ширину к этому элементу.
Это может использоваться как для значения высоты, так и для значения ширины.
- '500px' - примерная высота элемента. Может быть любым валидным
значением <length>.
*/
contain-intrinsic-size: auto none auto 500px;
}Добавьте обработчик события contentvisibilityautostatechange для приостановки или возобновления фоновых задач.
Событие
contentvisibilityautostatechangeне всплывает (bubble) в некоторых браузерах. Для надежной обработки этого события следует делать одно из двух:
- добавлять обработчик прямо к элементу с
content-visibility: auto;- использовать захватывающий обработчик (
{ capture: true }) при делегировании событий родительскому контейнеру.
const component = document.querySelector('.heavy-component');
// Вариант 1: прямой обработчик (рекомендуется)
component.addEventListener('contentvisibilityautostatechange', (event) => {
if (event.skipped) {
// Браузер пропустил рендеринг этого контента.
// Не выполняем тяжелые мутации или циклы анимации здесь.
stopSimulation();
pauseWebSocketPolling();
} else {
// Браузер собирается рендерить контент.
// Возобновляем работу, чтобы получить результат к моменту отображения.
startSimulation();
resumeWebSocketPolling();
}
});
// Вариант 2: захватывающий обработчик для делегирования событий
document.addEventListener('contentvisibilityautostatechange', (event) => {
if (event.target.matches('.heavy-component')) {
if (event.skipped) {
stopSimulation();
} else {
startSimulation();
}
}
}, { capture: true });Свойство content-visibility поддерживается всеми основными браузерами с 15.09.2025.
Свойство content-visibility и соответствующее событие contentvisibilityautostatechange являются прогрессивными улучшениями. В браузерах без их поддержки:
- свойство игнорируется, контент рендерится обычно;
- событие никогда не возникает, поэтому фоновые задачи продолжают выполняться в обычном режиме без оптимизаций.
Для приостановки задач в старых браузерах можно использовать IntersectionObserver:
// Резерв с помощью IntersectionObserver для старых браузеров
const target = document.getElementById('target-container');
// Проверяем поддержку content-visibility
const isSupported = 'contentVisibility' in document.documentElement.style;
if (!isSupported) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Элемент находится близко к экрану. Приступаем к работе
startSimulation();
} else {
// Элемент далеко от экрана. Приостанавливаем работу
stopSimulation();
}
});
}, {
// Используем rootMargin для запуска рендеринга перед "заходом" элемента на экран
rootMargin: '200px'
});
observer.observe(target);
}