콘텐츠 가시성: 렌더링 성능을 향상시키는 새로운 CSS 속성

화면 밖 콘텐츠의 렌더링을 건너뛰어 초기 로드 시간을 개선합니다.

Chromium 85에서 출시되는 content-visibility 속성은 페이지 로드 성능을 개선하는 데 가장 효과적인 새로운 CSS 속성 중 하나일 수 있습니다. content-visibility를 사용하면 사용자 에이전트가 필요할 때까지 레이아웃 및 페인팅을 포함한 요소의 렌더링 작업을 건너뛸 수 있습니다. 렌더링을 건너뛰므로 콘텐츠의 상당 부분이 화면을 벗어나면 content-visibility 속성을 활용하면 초기 사용자가 훨씬 빠르게 로드됩니다. 또한 화면의 콘텐츠와 더 빠르게 상호작용할 수 있습니다. 정말 깔끔하네요.

네트워크 결과를 나타내는 그림이 포함된 데모
이 자료 데모에서 분할된 콘텐츠 영역에 content-visibility: auto를 적용하면 초기 로드 시 렌더링 성능이 7배 향상됩니다. 자세한 내용을 알아보려면 계속 읽어보세요.

브라우저 지원

브라우저 지원

  • 85
  • 85
  • 124

소스

content-visibilityCSS 포함 사양 내의 프리미티브를 사용합니다. content-visibility는 현재 Chromium 85에서만 지원되고 Firefox용 '프로토타입 제작 가치'로 간주되지만 포함 사양은 대부분의 최신 브라우저에서 지원됩니다.

CSS 포함

CSS 포함의 핵심이자 가장 중요한 목표는 페이지의 나머지 부분과 DOM 하위 트리를 예측할 수 있도록 격리하여 웹 콘텐츠의 렌더링 성능을 개선하는 것입니다.

기본적으로 개발자는 페이지의 어떤 부분이 콘텐츠 집합으로 캡슐화되는지 브라우저에 알려줄 수 있으므로 브라우저가 하위 트리 외부의 상태를 고려하지 않고도 콘텐츠에 관해 추론할 수 있습니다. 격리된 콘텐츠가 포함된 콘텐츠(하위 트리)를 알면 브라우저에서 페이지 렌더링을 위한 최적화 결정을 내릴 수 있습니다.

CSS 포함에는 4가지 유형이 있으며 각 유형은 contain CSS 속성의 잠재적인 값이며 공백으로 구분된 값 목록에서 결합할 수 있습니다.

  • size: 요소에 크기를 포함하면 하위 요소를 검사할 필요 없이 요소의 상자를 배치할 수 있습니다. 즉, 요소의 크기만 필요한 경우 하위 요소의 레이아웃을 건너뛸 수 있습니다.
  • layout: 레이아웃 포함은 하위 요소가 페이지에 있는 다른 상자의 외부 레이아웃에 영향을 미치지 않는다는 것을 의미합니다. 이렇게 하면 다른 상자를 배치하기만 하려는 경우 하위 요소의 레이아웃을 건너뛸 수 있습니다.
  • style: 스타일 포함은 하위 요소뿐 아니라 여러 요소에 영향을 미칠 수 있는 속성이 요소 (예: 카운터)를 이스케이프하지 않도록 합니다. 이렇게 하면 다른 요소의 스타일을 계산하는 것이 전부인 경우 하위 요소의 스타일 계산을 건너뛸 수 있습니다.
  • paint: 페인트 격리는 포함 상자의 하위 요소가 경계 외부에 표시되지 않도록 합니다. 그 어떤 것도 요소를 오버플로할 수 없으며 요소가 화면 밖에 있거나 표시되지 않는 경우 하위 요소도 표시되지 않습니다. 이렇게 하면 요소가 화면을 벗어나면 하위 요소 페인팅을 건너뛸 수 있습니다.

content-visibility로 렌더링 작업 건너뛰기

적절한 세트가 지정되었을 때만 브라우저 최적화가 시작될 수 있으므로 어떤 포함 값을 사용할지 알아내기가 어려울 수 있습니다. 값을 사용하여 가장 효과적인 것을 확인하거나 content-visibility라는 다른 CSS 속성을 사용하여 필요한 요소를 자동으로 적용할 수 있습니다. content-visibility를 사용하면 개발자가 최소한의 노력으로 브라우저에서 제공할 수 있는 최대 성능 이점을 얻을 수 있습니다.

콘텐츠 공개 상태 속성은 여러 값을 허용하지만 auto는 즉각적인 성능 개선을 제공하는 값입니다. content-visibility: auto가 있는 요소는 layout, style, paint 포함을 얻습니다. 요소가 화면 밖에 있고 사용자와 관련이 없는 경우 (관련 요소는 하위 트리에 포커스 또는 선택 항목이 있는 요소임) size도 포함하게 됩니다 (또한 콘텐츠의 페인팅히트 테스트가 중지됩니다).

이 메시지는 무엇을 의미하나요? 즉, 요소가 화면 밖에 있으면 하위 요소가 렌더링되지 않습니다. 브라우저는 요소의 콘텐츠를 전혀 고려하지 않고 요소의 크기를 결정하며, 여기에서 중단합니다. 요소 하위 트리의 스타일 지정 및 레이아웃과 같은 대부분의 렌더링은 건너뜁니다.

요소가 표시 영역에 가까워지면 브라우저는 더 이상 size 억제를 추가하지 않고 요소의 콘텐츠 페인팅과 히트 테스트를 시작합니다. 이렇게 하면 사용자가 볼 수 있도록 제때 렌더링 작업을 실행할 수 있습니다.

접근성 관련 참고사항

content-visibility: auto의 기능 중 하나는 화면 밖 콘텐츠를 문서 객체 모델에서 사용할 수 있으므로 접근성 트리 (visibility: hidden와 달리)에서 계속 사용할 수 있다는 것입니다. 즉, 콘텐츠가 렌더링될 때까지 기다리거나 렌더링 성능을 저하시키지 않고 페이지에서 콘텐츠를 검색하고 페이지로 이동할 수 있습니다.

그러나 반대로 display: none 또는 visibility: hidden과 같은 스타일 기능이 있는 랜드마크 요소가 화면 밖에 있을 때도 접근성 트리에 표시됩니다. 이는 브라우저에서 표시 영역에 들어올 때까지 이러한 스타일을 렌더링하지 않기 때문입니다. 이러한 요소가 접근성 트리에 표시되어 복잡해지지 않도록 하려면 aria-hidden="true"도 추가해야 합니다.

예: 여행 블로그

이 예시에서는 여행 블로그 오른쪽의 기준을 정하고 content-visibility: auto을 왼쪽 분할 영역에 적용합니다. 초기 페이지 로드 시 렌더링 시간이 232ms에서 30ms 사이로 표시됩니다.

일반적으로 여행 블로그는 사진 몇 장과 설명 텍스트로 구성된 이야기 모음으로 구성됩니다. 일반적인 브라우저에서 여행 블로그로 이동할 때 다음과 같은 상황이 발생합니다.

  1. 페이지의 일부가 필요한 리소스와 함께 네트워크에서 다운로드됩니다.
  2. 브라우저는 콘텐츠가 사용자에게 표시되는지 고려하지 않고 페이지의 모든 콘텐츠의 스타일을 지정하고 배치합니다.
  3. 브라우저는 모든 페이지와 리소스가 다운로드될 때까지 1단계로 돌아갑니다.

2단계에서 브라우저는 모든 콘텐츠를 처리하여 변경되었을 수 있는 항목을 찾습니다. 새 업데이트로 인해 이동했을 수 있는 요소와 함께 새 요소의 스타일과 레이아웃을 업데이트합니다. 이것이 렌더링 작업입니다. 이 작업에는 시간이 걸립니다.

여행 블로그의 스크린샷
여행 블로그의 예. Codepen 데모를 참고하세요.

이제 블로그의 각 개별 이야기에 content-visibility: auto를 적용하면 어떻게 될지 생각해 보세요. 일반적인 루프는 동일합니다. 브라우저가 페이지의 청크를 다운로드하고 렌더링한다는 것입니다. 그러나 2단계에서 수행하는 작업량은 다릅니다.

콘텐츠 공개 상태를 사용하면 현재 사용자에게 표시되는 모든 콘텐츠 (화면에 표시됨)의 스타일을 지정하고 레이아웃을 적용합니다. 그러나 완전히 화면 밖에 있는 스토리를 처리할 때 브라우저는 렌더링 작업을 건너뛰고 요소 상자 자체의 스타일과 레이아웃만 지정합니다.

이 페이지를 로드하면 화면에 전체 화면 뉴스와 각 화면 밖 뉴스의 빈 상자가 포함된 것처럼 성능이 향상됩니다. 이 방법은 로드의 렌더링 비용을 50% 이상 절감할 것으로 예상되므로 성능이 훨씬 뛰어납니다. 이 예에서는 렌더링 시간이 232ms에서 30ms로 빨라졌습니다. 성능이 7배 향상됩니다.

이러한 이점을 누리기 위해 해야 할 일은 무엇인가요? 먼저 콘텐츠를 다음과 같이 섹션으로 나눕니다.

CSS 클래스를 사용하여 콘텐츠를 섹션으로 나누는 주석이 달린 스크린샷
content-visibility: auto를 수신하기 위해 story 클래스가 적용된 상태로 콘텐츠를 섹션으로 분할하는 예시입니다. Codepen 데모를 참고하세요.

그런 다음 섹션에 다음 스타일 규칙을 적용합니다.

.story {
  content-visibility: auto;
  contain-intrinsic-size: 1000px; /* Explained in the next section. */
}

contain-intrinsic-size를 사용하여 요소의 자연 크기 지정

content-visibility의 잠재적인 이점을 실현하려면 브라우저에서 콘텐츠의 렌더링 결과가 요소의 크기에 어떤 식으로든 영향을 미치지 않도록 크기 포함을 적용해야 합니다. 즉, 요소가 비어 있는 것처럼 배치됩니다. 일반 블록 레이아웃에 지정된 높이가 없는 요소는 높이가 0이 됩니다.

이는 스크롤바의 크기가 변경되어 높이가 0이 아닌 각 스토리에 의존하므로 이상적이지 않을 수 있습니다.

다행히 CSS는 또 다른 속성인 contain-intrinsic-size를 제공합니다. 이 속성은 크기 포함의 영향을 받는 경우 요소의 자연스러운 크기를 효과적으로 지정합니다. 이 예에서는 섹션의 높이와 너비의 추정치로 이를 1000px로 설정합니다.

즉, '내장 크기' 크기의 단일 하위 요소가 있는 것처럼 배치되어 크기가 지정되지 않은 div가 여전히 공간을 차지하도록 합니다. contain-intrinsic-size는 렌더링된 콘텐츠 대신 자리표시자 크기로 작동합니다.

Chromium 98 및 이후 버전에는 contain-intrinsic-size에 대한 새로운 auto 키워드가 있습니다. 지정하면 브라우저가 마지막으로 렌더링된 크기(있는 경우)를 기억하고 개발자가 제공한 자리표시자 크기 대신 이 크기를 사용합니다. 예를 들어 contain-intrinsic-size: auto 300px를 지정한 경우 요소는 각 크기에서 300px 고유 크기 조정으로 시작하지만 요소의 콘텐츠가 렌더링되면 렌더링된 고유 크기가 유지됩니다. 이후의 모든 렌더링 크기 변경사항도 저장됩니다. 실제로 content-visibility: auto가 적용된 요소를 스크롤했다가 다시 화면 밖으로 스크롤하면 이상적인 너비와 높이가 자동으로 유지되고 자리표시자 크기로 되돌아가지 않습니다. 이 기능은 특히 무한 스크롤러에 유용하며, 이제 사용자가 페이지를 탐색함에 따라 시간이 지남에 따라 크기 추정을 자동으로 개선할 수 있습니다.

content-visibility: hidden로 콘텐츠 숨기기

콘텐츠가 화면에 있는지 여부와 관계없이 캐시된 렌더링 상태의 이점을 활용하려면 콘텐츠가 렌더링되지 않은 상태로 유지하려면 어떻게 해야 할까요? content-visibility: hidden를 입력합니다.

content-visibility: hidden 속성은 content-visibility: auto가 화면 밖에서 하는 것과 마찬가지로 렌더링되지 않은 콘텐츠와 캐시된 렌더링 상태의 모든 이점을 제공합니다. 그러나 auto와 달리 화면에 렌더링이 자동으로 시작되지는 않습니다.

이렇게 하면 더 세부적으로 관리할 수 있으므로 요소의 콘텐츠를 숨기고 나중에 빠르게 숨기기를 해제할 수 있습니다.

요소의 콘텐츠를 숨기는 다른 일반적인 방법과 비교해 보세요.

  • display: none: 요소를 숨기고 렌더링 상태를 삭제합니다. 즉, 요소 숨기기 해제는 동일한 콘텐츠로 새 요소를 렌더링하는 것만큼 비용이 듭니다.
  • visibility: hidden: 요소를 숨기고 렌더링 상태를 유지합니다. 이렇게 해도 문서에서 요소와 하위 트리가 여전히 기하학적 공간을 차지하고 클릭할 수 있기 때문에 실제로 요소가 삭제되지는 않습니다. 또한 숨겨진 경우에도 필요할 때마다 렌더링 상태를 업데이트합니다.

반면 content-visibility: hidden는 렌더링 상태를 유지하면서 요소를 숨깁니다. 따라서 발생해야 하는 변경사항이 있는 경우 요소가 다시 표시될 때만 (즉, content-visibility: hidden 속성이 삭제됨) 변경사항이 발생합니다.

content-visibility: hidden의 좋은 사용 사례는 고급 가상 스크롤러를 구현하고 레이아웃을 측정할 때입니다. 단일 페이지 애플리케이션 (SPA)에도 적합합니다. 비활성 앱 뷰는 표시를 방지하지만 캐시된 상태를 유지하기 위해 content-visibility: hidden가 적용된 상태로 DOM에 남아 있을 수 있습니다. 이렇게 하면 뷰가 다시 활성화될 때 빠르게 렌더링할 수 있습니다.

다음 페인트와의 상호작용 (INP)에 미치는 영향

INP는 페이지가 사용자 입력에 안정적으로 응답하는지 평가하는 측정항목입니다. 응답성은 렌더링 작업을 비롯하여 기본 스레드에서 발생하는 과도한 작업의 영향을 받을 수 있습니다.

특정 페이지에서 렌더링 작업을 줄일 수 있을 때마다 기본 스레드가 사용자 입력에 더 빠르게 응답할 수 있는 기회를 얻게 됩니다. 여기에는 렌더링 작업이 포함되며, 필요한 경우 content-visiblity CSS 속성을 사용하면 렌더링 작업을 줄일 수 있습니다(특히 대부분의 렌더링 및 레이아웃 작업이 완료되는 시작 시).

렌더링 작업을 줄이면 INP에 직접적인 영향을 줍니다. 사용자가 content-visibility 속성을 올바르게 사용하여 오프스크린 요소의 레이아웃과 렌더링을 지연하는 페이지와 상호작용하려고 하면 기본 스레드가 사용자에게 표시되는 중요한 작업에 응답할 수 있습니다. 경우에 따라 이렇게 하면 페이지의 INP가 개선될 수 있습니다.

결론

content-visibility 및 CSS 포함 사양은 CSS 파일에서 놀라운 성능 향상 효과를 얻을 수 있음을 의미합니다. 이러한 속성에 대한 자세한 내용은 다음을 참조하세요.