content-visibility: the new CSS property that boosts your rendering performance
본 게시글은 https://web.dev/content-visibility/ 의 글을 번역 게시하였습니다.
8월 25일 Chrome 85에 추가된 content-visibility
속성에 대해 정리했습니다.
화면 밖 콘텐츠의 렌더링을 생략함으로써 초기 로드 시간을 개선합니다.
Chrome 85에 새로 적용된 content-visibility
속성은 페이지 로드 성능을 향상시키는 가장 효과적인 새로운 CSS 속성 중 하나입니다. content-visibility
는 UserAgent가 layout, painting을 포함한 요소의 렌더링 작업을 필요로할 때까지 생략할 수 있도록 합니다. 콘텐츠의 대부분이 화면 밖에 있을 때, content-visibility
을 활용해서 렌더링을 생략하게 되면 사용자의 초기 로드 시간이 훨씬 빨라집니다. 또한, 화면 내 콘텐츠와 더 빠르게 상호작용할 수 있습니다.
콘텐츠에 content-visibility: auto
를 적용하면 초기 로드 시 렌더링 성능이 7배 향상됩니다.
Browser support
content-visibility
는 CSS Containment Spec에 의존하고 있습니다. 현재는 Chrome 85만 지원하지만(Firefox는 “worth prototyping” 으로 간주합니다.), Containment Spec은 대부분의 모던 브라우저에서 지원하고 있습니다.
CSS Containment
CSS Containment의 핵심이자 목적은 페이지 전체에서 DOM subtree의 분리를 제공하여 렌더링 성능을 향상시키는 것 입니다.
기본적으로 개발자는 브라우저에게 페이지의 어떤 부분이 캡슐화되어 있는지 알려주어, 브라우저로 하여금 해당 콘텐츠가 외부 요소의 상태를 고려하지 않아도 된다는 것을 알 수 있도록 합니다. 분리된 콘텐츠를 알면 브라우저는 페이지 렌더링을 최적화할 수 있습니다.
CSS containment의 4가지 유형이 있고, 각 유형은 contain
속성의 잠재적 값이며 공백으로 구분하여 조합할 수 있습니다.
size
: Size containment는 자손 요소를 확인하지 않고도 요소의 크기를 계산할 수 있습니다. 이는 요소의 크기 확인만 필요할 경우 자손 요소의 레이아웃을 생략할 수 있습니다.layout
: Layout containment는 자손 요소가 외부 레이아웃에 영향을 주지 않음을 의미합니다. 이는 다른 요소의 레이아웃만 필요할 경우에 자손 요소의 레이아웃을 생략할 수 있습니다.style
: Style containment는counters
,qoutes
와 같이 요소에 영향을 미칠 수 있는 속성이 요소를 벗어나지 못하도록 합니다. 이는 다른 요소의 스타일 계산을 원하는 경우라면, 자손 요소의 스타일 계산을 생략할 수 있습니다.paint
: Paint containment는 자손 요소가 overflow될 수 없으며, 요소가 화면 밖에 있거나 표시되지 않는 경우 자손 요소도 표시되지 않습니다. 이는 요소가 화면 밖에 있는 경우 자손 요소의 painting 작업을 생략할 수 있습니다.
Skipping rendering work with content-visibility
브라우저 최적화는 적절한 값이 지정되어야 효과가 있으므로 어떤 값을 써야할지 어려울 수 있습니다. 어떤 값이 가장 효과적인지 직접 적용하면서 확인하거나 또는 다른 속성인 content-visibility
을 사용하여 자동으로 적용할 수 있습니다. content-visibility
는 최소한의 노력으로 최대 성능 향상을 이룰수 있게 합니다.
content-visibility
속성에는 여러 값이 있지만, auto
는 즉시 성능 향상을 제공하는 값입니다. content-visibility: auto
는 layout
, style
and paint
Containment의 효과가 있습니다. 요소가 화면 밖이면(선택되었거나 포커스를 받는 것과 같이 사용자 액션과 관련이 없는 경우) size
Containment 효과도 얻습니다.(요소의 painting과 hit-testing도 중지합니다.)
이것이 무엇을 의미할까요? 바로 요소가 화면 밖에 있는 경우 자손 요소를 렌더링 하지 않습니다. 브라우저는 요소의 내용을 고려하지 않고 크기를 결정합니다. 자손 요소는 styling, layout과 같은 대부분의 렌더링 작업을 생략합니다.
요소가 뷰포트에 접근하면 브라우저는 더 이상 size
containment를 유지하지 않고 사용자가 볼 수 있도록 렌더링 작업(painting과 hit-testing)을 진행합니다.
Example: a travel blog
위의 여행 블로그는 일반적으로 몇 장의 사진과 글들로 구성된 문단들로 이루어져 있습니다. 다음은 페이지 로드 시에 브라우저에서 일어나는 일입니다.
- 페이지의 일부를 필요한 리소스와 함께 네트워크를 통해 다운로드 합니다.
- 브라우저는 사용자에게 보여지는지 여부와 관계없이 모든 콘텐츠의 스타일, 레이아웃 작업을 진행합니다.
- 페이지 전부와 모든 리소스가 다운로드 될때까지 반복합니다.
2단계에서 브라우저는 변경되었을 수 있는 부분을 찾기 위해 모든 콘텐츠를 처리합니다. 새로운 업데이트의 결과로 새 요소와 그에 따라 변경되었을 요소의 스타일, 레이아웃을 업데이트 합니다. 이것이 렌더링 작업이며 시간이 걸리는 일입니다.
이제 이 블로그의 각 문단에 content-visibility: auto
를 선언하면 어떻게 될지 생각해 보세요. 일반적인 단계 진행은 똑같습니다. 브라우저가 페이지의 일부를 다운로드하고 렌더링합니다. 그러나 차이점은 2단계에서 수행하는 작업의 양에 있습니다.
content-visibility
를 통해 화면 내 콘텐츠의 스타일과 레이아웃 작업을 진행합니다. 하지만 요소가 완전히 화면 밖에 있는 경우라면 브라우저는 오직 해당 요소 박스의 스타일과 레이아웃만 처리하고 다른 렌더링 작업은 생략합니다.
이 페이지의 로딩 성능은 마치 화면 내 콘텐츠 전부와 화면 밖 콘텐츠는 빈 상자만 로딩 하는 것과 같습니다. 이는 예상되는 렌더링 비용에서 50% 이상을 감소하는 효과로 훨씬 더 나은 성능을 발휘합니다. 위 예제에서는 렌더링 시간이 232ms에서 30ms로 7배 빨라졌습니다.
이런 효과를 누리기 위해 우리가 할 일은 무엇일까요? 먼저 콘텐츠를 영역으로 나눕니다.
그리고 콘텐츠 영역에 다음과 같이 스타일 규칙을 선언합니다.
.story {
content-visibility: auto;
contain-intrinsic-size: 1000px; /* 다음 섹션에서 셜명합니다. */
}
콘텐츠가 화면 안팎으로 이동하게 되면 필요에 따라 렌더링이 시작되고 중지됩니다. 하지만 브라우저는 가능한 렌더링 작업을 저장하기 때문에 동일한 콘텐츠를 반복해서 다시 렌더링 해야한다는 의미는 아닙니다.
Specifying the natural size of an element with contain-intrinsic-size
content-visibility
의 잠재적인 이점을 실현하기 위해 브라우저는 콘텐츠의 렌더링 결과가 요소 크기에 영향을 미치지 않도록 size containment를 적용해야 합니다. 즉, 요소는 비어있는 것처럼 배치되는데 일반적으로 block 요소의 높이가 지정되지 않은 경우 높이는 0이 됩니다.
결국 스크롤바는 각 문단 높이에 의존하게 되어 이동하므로 이상적인 상황은 아닙니다.
다행히도, CSS에는 contain-intrinsic-size
속성을 제공합니다. 이 속성은 요소가 size containment의 영향을 받더라도 요소를 자연스러운 크기대로 효과적으로 지정할 수 있습니다. 이 예에서는 문단의 크기를 1000px
로 임의 지정했습니다.
즉, 크기가 지정되지 않은 div가 공간을 차지할 수 있도록 “intrinsic-size”를 가진 자식 요소가 있는 것처럼 배치됩니다. contain-intrinsic-size
는 렌더링 된 콘텐츠 대신 placeholder로서 동작합니다.
Hiding content with content-visibility: hidden
cached 렌더링의 장점을 활용하면서 콘텐츠가 화면에 있는지 여부와 관계없이 렌더링하지 않으려면 어떻게해야 할까요? content-visibility: hidden
을 사용하세요.
content-visibility: hidden
속성은 마치 content-visibility: auto
의 화면 밖 콘텐츠처럼 unrendered와 cached 렌더링의 장점을 제공합니다. 그러나 auto
와 달리 콘텐츠가 화면 안으로 들어오더라도 자동으로 렌더링하지 않습니다.
이런 제어를 통해 요소를 숨겼다가 나중에 신속하게 다시 표시할 수 있습니다.
요소를 숨기는 다른 일반적인 방법들과 비교해봅시다.
display: none
: 요소를 숨기고 렌더링 상태를 제거합니다. 즉, 해당 요소를 표시하기 위해서는 새 요소를 렌더링 하는 것만큼 비용이 많이 듭니다.visibility: hidden
: 요소를 숨기면서 렌더링 상태는 유지합니다. 이것은 문서에서 요소를 실제로 제거하지 않으며, 여전히 페이지에서 공간을 차지하고 클릭할 수 있는 상태입니다. 또한 숨겨져 있더라도 필요하면 렌더링 상태를 업데이트합니다.
반면 content-visibility: hidden
은 렌더링 상태를 유지하면서 요소를 숨기는데, 상태를 변경해야 할 일이 생기면 요소가 다시 화면에 표시될 때만 변경합니다.(예로 content-visibility: hidden
속성이 제거되는 경우)
content-visibility: hidden
의 좋은 사례는 가상의 스크롤러가 구현된 상태에서 레이아웃을 측정할 때입니다.
Conclusion
content-visibility
및 CSS Containment Spec은 몇 가지 흥미로운 성능 향상에 대한 것을 CSS에서 바로 적용할 수 있습니다. 자세한 내용은 다음을 확인해주세요.
0개의 댓글