Web 功能:
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 事件属于渐进增强。在不支持这些功能的浏览器中:
- 系统会忽略该 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);
}