브라우저에서 구성요소가 렌더링되지 않을 때 시스템 리소스와 배터리 수명을 보존하기 위해 무거운 백그라운드 작업을 일시중지합니다.
개요
content-visibility: auto 속성을 사용하면 브라우저가 표시 영역에서 멀리 떨어진 요소의 렌더링 계산을 건너뛸 수 있습니다. 브라우저가 요소의 렌더링을 건너뛰거나 재개하기로 결정하면 해당 요소에서 contentvisibilityautostatechange 이벤트를 실행합니다.
이 이벤트를 수신 대기하면 <canvas> 애니메이션, WebGL 렌더링, 고주파 WebSocket 데이터 폴링과 같이 비용이 많이 드는 작업이 필요하지 않을 때 일시중지하고 브라우저가 콘텐츠를 표시할 준비가 되면 적시에 재개할 수 있습니다.
contentvisibilityautostatechange 대 IntersectionObserver
어떤 API를 언제 사용해야 하는지 이해하는 것이 중요합니다.
- 뷰포트에서 요소의 정확한 시각적 공개 상태와 관련된 애플리케이션 로직에
IntersectionObserver를 사용합니다 (예: 지연 로드 데이터, 무한 스크롤 트리거). - 복잡한 캔버스 업데이트나 대규모 DOM 변형과 같은 렌더링이 많은 작업에는
contentvisibilityautostatechange를 사용합니다. 이 이벤트는 브라우저의 내부 렌더링 수명 주기와 직접 연결됩니다. 브라우저는 요소가 화면에 실제로 표시되기 전에 렌더링을 시작하는 경우가 많습니다 (사전 렌더링 여백). 이 이벤트는 이 시점을 알려주어 콘텐츠를 표시할 준비가 되었는지 확인합니다.
구현
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);
}