Cumulative Layout Shift (CLS)

브라우저 지원

  • 77
  • 79
  • x
  • x

소스

<ph type="x-smartling-placeholder">

예기치 않은 레이아웃 변경은 여러 면에서 사용자 환경에 지장을 줄 수 있습니다. 텍스트가 갑자기 이동하는 경우 사용자가 읽는 위치를 놓칠 수도 있고, 사용자가 잘못된 링크나 버튼을 클릭하게 되는 경우도 있습니다. 경우에 따라 이렇게 하면 심각한 손상을 입을 수도 있습니다.

<ph type="x-smartling-placeholder">
</ph>
레이아웃이 갑작스럽게 바뀌면 사용자가 의도한 많은 순서를 확인하게 됨 취소합니다.

일반적으로 리소스가 비동기식으로 로드되거나 DOM 요소가 기존 콘텐츠보다 먼저 페이지에 동적으로 추가되는 경우 페이지 콘텐츠가 예기치 않게 이동합니다. 레이아웃 변경의 원인으로는 크기를 알 수 없는 이미지나 동영상, 초기 대체 값보다 크거나 작게 렌더링되는 글꼴, 자동으로 크기가 조절되는 서드 파티 광고 또는 위젯 등이 있습니다.

개발 시 사이트가 작동하는 방식과 사용자가 이를 경험하는 방식의 차이로 인해 문제가 더 악화됩니다. 예를 들면 다음과 같습니다.

  • 맞춤설정 콘텐츠 또는 서드 파티 콘텐츠는 개발 단계와 프로덕션 단계에서 다르게 작동하는 경우가 많습니다.
  • 테스트 이미지는 이미 개발자의 브라우저 캐시에 있는 경우가 많지만 최종 사용자에게 로드하는 데 시간이 더 오래 걸립니다.
  • 로컬에서 실행되는 API 호출은 매우 빠른 경우가 많아 눈에 띄지 않는 개발 지연이 프로덕션 단계에서 상당히 커질 수 있습니다.

누적 레이아웃 변경 (CLS) 측정항목은 실제 사용자에게 발생하는 빈도를 측정하여 이 문제를 해결하는 데 도움이 됩니다.

CLS란 무엇인가요?

CLS는 페이지의 전체 수명 주기 동안 발생하는 모든 예상치 못한 레이아웃 변경에 대한 최대 버스트의 레이아웃 변경 점수를 측정합니다.

레이아웃 변경은 표시되는 요소가 렌더링된 한 프레임에서 다음 프레임으로 위치를 변경할 때마다 발생합니다. 개별 레이아웃 변경 점수를 계산하는 방법에 관한 자세한 내용은 이 가이드의 뒷부분에서 다룹니다.

세션 윈도우라고 하는 레이아웃 변경 버스트는 하나 이상의 개별 레이아웃 변경이 각 이동 사이에 1초 미만에서 최대 5초 이내에 연속적으로 발생하는 경우를 의미합니다.

가장 큰 버스트는 해당 기간 내의 모든 레이아웃 변경의 최대 누적 점수가 포함된 세션 기간입니다.

<ph type="x-smartling-placeholder">
</ph>
세션 기간의 예 파란색 막대는 각 레이아웃 변경의 점수를 나타냅니다.
를 통해 개인정보처리방침을 정의할 수 있습니다. <ph type="x-smartling-placeholder">

좋은 CLS 점수란 무엇인가요?

우수한 사용자 환경을 제공하려면 사이트의 CLS 점수가 0.1 이하가 되도록 노력해야 합니다. 대부분의 사용자가 이 목표를 달성할 수 있도록 모바일과 데스크톱 기기별로 분류된 페이지 로드의 75번째 백분위수를 측정하는 것이 좋습니다.

<ph type="x-smartling-placeholder">
</ph> 좋은 CLS 값은 0.1 이하이고, 낮은 값은 0.25보다 크며, 그 사이의 모든 값은 개선이 필요합니다.
적절한 CLS 값은 0.1 이하입니다. 나쁨 값은 0.25보다 큽니다.

이 권장사항의 이면에 있는 연구 및 방법론에 관한 자세한 내용은 Core Web Vitals 측정항목 기준점 정의를 참고하세요.

레이아웃 변경 세부정보

레이아웃 변경은 Layout Instability API로 정의되며, 이 API는 표시 영역 내에 표시되는 요소가 두 프레임 간에 시작 위치 (예: 기본 쓰기 모드에서 상단 및 왼쪽 위치)를 변경할 때마다 layout-shift 항목을 보고합니다. 이러한 요소는 불안정한 요소로 간주됩니다.

레이아웃 변경은 기존 요소의 시작 위치가 변경되는 경우에만 발생합니다. 새 요소가 DOM에 추가되거나 기존 요소의 크기가 변경되는 경우 레이아웃 변경으로 계산되지 않습니다. 단, 변경으로 인해 표시되는 다른 요소가 시작 위치를 변경하지 않아야 합니다.

레이아웃 변경 점수

브라우저는 레이아웃 변경 점수를 계산하기 위해 표시 영역 크기와 렌더링된 두 프레임 간의 표시 영역에서 불안정한 요소의 움직임을 확인합니다. 레이아웃 변경 점수는 해당 움직임의 두 측정값인 영향 비율거리 비율 (모두 아래에 정의됨)의 곱입니다.

layout shift score = impact fraction * distance fraction

영향 비율

영향 비율불안정한 요소가 두 프레임 사이의 표시 영역 영역에 미치는 영향을 측정합니다.

특정 프레임의 영향 비율은 표시 영역의 총 면적에 대한 비율로 해당 프레임과 이전 프레임의 불안정한 모든 요소의 보이는 영역의 조합입니다.

<ph type="x-smartling-placeholder">
</ph> 불안정한 요소 1개가 포함된 영향 비율 예 <ph type="x-smartling-placeholder">
</ph> 요소의 위치가 변경되면 이전 위치와 현재 위치가 모두 영향 비율에 반영됩니다.

위 이미지에는 한 프레임에서 표시 영역의 절반을 차지하는 요소가 있습니다. 그런 다음 다음 프레임에서 요소가 표시 영역 높이의 25% 만큼 아래로 이동합니다. 점선으로 표시된 빨간색 직사각형은 두 프레임에서 요소의 가시 영역의 합집합을 나타내며 이 경우 전체 표시 영역의 75% 이므로 영향 비율0.75입니다.

거리 비율

레이아웃 변경 점수 방정식의 다른 부분은 불안정한 요소가 표시 영역을 기준으로 이동한 거리를 측정합니다. 거리 비율은 프레임에서 이동한 불안정한 요소가 이동한 최대 가로 또는 세로 거리를 표시 영역의 최대 크기 (너비 또는 높이 중 더 큰 값)로 나눈 값입니다.

<ph type="x-smartling-placeholder">
</ph> 불안정한 요소 하나가 있는 거리 비율 예 <ph type="x-smartling-placeholder">
</ph> 거리 비율은 요소가 표시 영역에서 얼마나 멀리 이동한지 측정합니다.

이전 예에서 가장 큰 표시 영역 크기는 높이이고 불안정한 요소는 표시 영역 높이의 25% 만큼 이동하여 거리 비율이 0.25가 됩니다.

따라서 이 예에서 영향 비율0.75이고 거리 비율0.25이므로 레이아웃 변경 점수0.75 * 0.25 = 0.1875입니다.

<ph type="x-smartling-placeholder">

다음 예는 기존 요소에 콘텐츠를 추가하면 레이아웃 변경 점수에 어떤 영향을 미치는지 보여줍니다.

<ph type="x-smartling-placeholder">
</ph> 여러 안정 요소 및 _불안정한 요소_가 있는 레이아웃 변경 예 <ph type="x-smartling-placeholder">
</ph> 회색 상자의 하단에 버튼을 추가하면 녹색 상자가 아래로 밀려서 부분적으로 표시 영역 밖으로 나갑니다.

이 예에서 회색 상자의 크기는 변경되지만 시작 위치는 변경되지 않으므로 불안정한 요소가 아닙니다.

'Click Me!'는 버튼은 이전에 DOM에 없었으므로 시작 위치도 변경되지 않습니다.

그러나 녹색 상자의 시작 위치는 변경되지 않지만 부분적으로 표시 영역 밖으로 이동되었으므로 영향 비율을 계산할 때 표시되지 않는 영역은 고려되지 않습니다. 두 프레임에서 녹색 상자에 표시되는 영역(빨간색 점선으로 표시된 직사각형으로 표시됨)의 합집합은 첫 번째 프레임의 녹색 상자 영역(표시 영역의 50%)과 동일합니다. 영향 비율0.5입니다.

거리 비율은 보라색 화살표로 표시됩니다. 녹색 상자가 표시 영역의 약 14% 아래로 이동했으므로 거리 비율0.14가 됩니다.

레이아웃 변경 점수는 0.5 x 0.14 = 0.07입니다.

다음 예는 여러 개의 불안정한 요소가 페이지의 레이아웃 변경 점수에 어떤 영향을 미치는지 보여줍니다.

<ph type="x-smartling-placeholder">
</ph> 안정적인 _요소와 _불안정한 요소_와 표시 영역 클리핑이 있는 레이아웃 변경 예 <ph type="x-smartling-placeholder">
</ph> 정렬된 목록에 더 많은 이름이 나타날수록 기존 이름은 알파벳순으로 이동합니다.

위 이미지의 첫 번째 프레임에는 동물에 대한 API 요청의 결과 4개가 알파벳순으로 정렬되어 있습니다. 두 번째 프레임에서는 정렬된 목록에 더 많은 결과가 추가됩니다.

목록의 첫 번째 항목('Cat')은 프레임 간에 시작 위치를 변경하지 않으므로 안정적입니다. 마찬가지로 목록에 추가된 새 항목은 이전에 DOM에 없었으므로 시작 위치도 변경되지 않습니다. 하지만 '개', '말', '얼룩말'이라는 라벨이 지정된 항목에는 모두 시작 위치를 이동하여 불안정한 요소가 됩니다.

다시 말하지만 빨간색 점선 직사각형은 이 세 가지 불안정한 요소의 합집합을 나타냅니다. 표시 영역 전후에 표시하며, 이 경우에는 표시 영역 면적의 약 60% 입니다 (0.60영향 비율).

화살표는 불안정한 요소가 시작 위치에서 이동한 거리를 나타냅니다. '얼룩말' 요소가 표시 영역 높이의 약 30% 만큼 가장 많이 이동했습니다. 따라서 이 예의 거리 비율0.3가 됩니다.

레이아웃 변경 점수는 0.60 x 0.3 = 0.18입니다.

예상된 레이아웃 변경과 예기치 않은 레이아웃 변경

모든 레이아웃 변경이 나쁜 것은 아닙니다. 실제로 많은 동적 웹 애플리케이션은 페이지에서 요소의 시작 위치를 자주 변경합니다. 레이아웃 변경은 사용자가 예상하지 못한 경우에만 좋지 않습니다.

사용자가 시작한 레이아웃 변경

사용자 상호작용 (예: 링크 클릭 또는 탭, 버튼 누르기, 검색창에 입력)에 대한 반응으로 발생하는 레이아웃 전환은 일반적으로 사용자의 관계가 명확하게 드러나는 상호작용에 충분히 가깝게 발생하는 경우 문제가 되지 않습니다.

예를 들어 사용자 상호작용이 완료하는 데 다소 시간이 걸릴 수 있는 네트워크 요청을 트리거하는 경우, 요청이 완료될 때 레이아웃 변경을 방지하기 위해 즉시 공간을 만들고 로드 표시기를 표시하는 것이 가장 좋습니다. 사용자는 무언가가 로드되고 있다는 것을 모르거나 리소스가 언제 준비될지 모른다면 기다리는 동안 다른 무언가를 클릭하려고 할 수 있습니다. 무언가가 아래로 움직일 수도 있습니다.

사용자 입력 후 500밀리초 이내에 발생하는 레이아웃 변경에는 hadRecentInput 플래그가 설정되어 계산에서 제외될 수 있습니다.

<ph type="x-smartling-placeholder">

애니메이션 및 전환

애니메이션과 전환은 제대로 수행되면 사용자가 당황하지 않고 페이지의 콘텐츠를 업데이트할 수 있는 좋은 방법입니다. 페이지에서 갑작스럽고 예기치 않게 이동하는 콘텐츠는 거의 항상 사용자 환경을 저하시킵니다. 그러나 한 위치에서 다음 위치로 점진적이고 자연스럽게 이동하는 콘텐츠는 사용자가 상황을 더 잘 이해하고 상태 변경 사이를 이동하는 데 도움이 되는 경우가 많습니다.

일부 사이트 방문자는 애니메이션으로 인한 효과나 주의력 저하를 경험할 수 있으므로 prefers-reduced-motion 브라우저 설정을 준수하시기 바랍니다.

CSS transform 속성을 사용하면 레이아웃 변경을 트리거하지 않고도 요소에 애니메이션을 적용할 수 있습니다.

  • heightwidth 속성을 변경하는 대신 transform: scale()를 사용합니다.
  • 요소를 이동하려면 top, right, bottom 또는 left 속성을 변경하지 말고 transform: translate()를 대신 사용하세요.

CLS 측정 방법

CLS는 실습이나 현장에서 측정할 수 있으며 다음 도구에서 사용할 수 있습니다.

<ph type="x-smartling-placeholder">

현장 도구

실습 도구

JavaScript에서 레이아웃 변경 측정

JavaScript에서 레이아웃 변경을 측정하려면 Layout Instability API를 사용합니다.

다음 예시에서는 layout-shift 항목을 콘솔에 로깅하는 PerformanceObserver를 만드는 방법을 보여줍니다.

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('Layout shift:', entry);
  }
}).observe({type: 'layout-shift', buffered: true});

JavaScript에서 CLS 측정

JavaScript에서 CLS를 측정하려면 예상치 못한 layout-shift 항목을 세션으로 그룹화하고 최대 세션 값을 계산해야 합니다. CLS 계산 방법에 관한 참조 구현이 포함된 web vitals JavaScript 라이브러리 소스 코드를 참고하세요.

대부분의 경우 페이지 로드 취소 시점의 현재 CLS 값은 해당 페이지의 최종 CLS 값이지만 다음 섹션에 설명된 몇 가지 중요한 예외가 있습니다. web vitals JavaScript 라이브러리는 Web API의 제한 내에서 이를 최대한 많이 고려합니다.

측정항목과 API의 차이점

  • 페이지가 백그라운드에서 로드되거나 브라우저에서 콘텐츠를 칠하기 전에 배경에 있는 경우 CLS 값을 보고하면 안 됩니다.
  • 페이지가 뒤로-앞으로 캐시에서 복원되면 사용자가 고유한 페이지 방문으로 경험하므로 CLS 값을 0으로 재설정해야 합니다.
  • API는 iframe 내에서 발생하는 이동에 대해 layout-shift 항목을 보고하지 않지만 측정항목은 페이지 사용자 환경의 일부이므로 보고하지 않습니다. 이는 CrUX와 RUM의 차이점으로 표시될 수 있습니다. CLS를 올바르게 측정하려면 이를 고려해야 합니다. 하위 프레임은 API를 사용하여 집계를 위해 layout-shift 항목을 상위 프레임에 보고할 수 있습니다.

이러한 예외 외에도 CLS는 페이지의 전체 수명을 측정하기 때문에 복잡성이 추가됩니다.

  • 사용자는 탭을 며칠, 몇 주, 몇 개월 동안 매우 오랫동안 열어 둘 수 있습니다. 실제로 사용자는 탭을 결코 닫지 않을 수도 있습니다.
  • 모바일 운영체제에서 브라우저는 일반적으로 백그라운드 탭에 대해 페이지 로드 취소 콜백을 실행하지 않으므로 '최종' 값으로 사용됩니다.

이러한 경우를 처리하려면 페이지가 백그라운드 상태일 때나 페이지가 언로드될 때마다 (visibilitychange 이벤트가 두 시나리오에 모두 해당) CLS를 보고해야 합니다. 그러면 이 데이터를 수신하는 분석 시스템이 백엔드에서 최종 CLS 값을 계산해야 합니다.

개발자는 이러한 모든 사례를 직접 기억하고 고심할 필요 없이 web-vitals JavaScript 라이브러리를 사용하여 CLS를 측정할 수 있습니다. CLS는 iframe 사례를 제외하고 위에서 언급된 모든 항목을 처리합니다.

import {onCLS} from 'web-vitals';

// Measure and log CLS in all situations
// where it needs to be reported.
onCLS(console.log);

CLS 개선 방법

현장에서 레이아웃 변경을 식별하고 실험실 데이터를 사용하여 최적화하는 방법에 관한 자세한 내용은 CLS 최적화 가이드를 참고하세요.

추가 리소스

변경 로그

가끔 측정항목을 측정하는 데 사용되는 API에서 버그가 발견되며, 측정항목 자체의 정의에서도 버그가 발견됩니다. 그 결과, 때때로 변경이 이루어져야 하며, 내부 보고서 및 대시보드에서 이러한 변경사항이 개선되거나 회귀로 나타날 수 있습니다.

이를 관리하는 데 도움이 되도록 이러한 측정항목의 구현 또는 정의에 대한 모든 변경사항이 이 변경 로그에 표시됩니다.

이러한 측정항목에 관한 의견이 있으면 web-vitals-feedback Google 그룹에 의견을 보내주세요.