레이아웃 변경 디버그

레이아웃 변경을 식별하고 수정하는 방법을 알아봅니다.

Katie Hempenius
Katie Hempenius

이 도움말의 첫 번째 부분에서는 레이아웃 전환을 디버그하기 위한 도구를 설명하고, 두 번째 부분에서는 레이아웃 전환의 원인을 파악할 때 사용할 사고 과정을 설명합니다.

도구

Layout Instability API

Layout Instability API는 레이아웃 변경을 측정하고 보고하기 위한 브라우저 메커니즘입니다. DevTools를 비롯한 레이아웃 전환을 디버그하기 위한 모든 도구는 궁극적으로 Layout Instability API를 기반으로 빌드됩니다. 하지만 Layout Instability API를 직접 사용하면 유연성 덕분에 강력한 디버깅 도구가 됩니다.

사용

이전에 생성한 것과 동일한 코드 스니펫레이아웃 변경 횟수 (CLS)가 레이아웃 변경을 디버그하는 데 사용됩니다 아래 스니펫은 레이아웃에 관한 정보를 로깅합니다. 콘솔로 이동합니다 이 로그를 검사하면 레이아웃 전환이 발생한 시점, 위치, 방식에 관한 정보를 확인할 수 있습니다.

let cls = 0;
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

이 스크립트를 실행할 때는 다음 사항에 유의하세요.

  • buffered: true 옵션은 PerformanceObserver 브라우저의 성능 항목을 확인하여 버퍼 이전에 관찰자가 생성한 성능 항목이 초기화하지 않아도 됩니다 따라서 PerformanceObserver는 초기화 전후에 발생한 레이아웃 전환을 모두 보고합니다. 보관 명심해야 합니다. 초기 레이아웃 변경은 보고 백로그를 반영할 수 있습니다. 있습니다.
  • 성능에 영향을 주지 않기 위해 PerformanceObserver는 기본 스레드가 레이아웃 변경을 보고하지 않고 유휴 상태일 수 있습니다. 결과적으로 기본 스레드가 바쁜 상태라면 레이아웃이 실제 스레드와 로그에 기록될 때 발생합니다
  • 이 스크립트는 사용자 입력으로부터 500ms 이내에 발생한 레이아웃 변경을 무시합니다. CLS에 포함되지 않습니다

레이아웃 전환에 관한 정보는 LayoutShiftLayoutShiftAttribution 인터페이스라는 두 API를 조합하여 보고됩니다. 이러한 각 인터페이스는 참조하세요

LayoutShift

각 레이아웃 변경은 LayoutShift 인터페이스를 사용하여 보고됩니다. 이 다음과 같이 표시됩니다.

duration: 0
entryType: "layout-shift"
hadRecentInput: false
lastInputTime: 0
name: ""
sources: (3) [LayoutShiftAttribution, LayoutShiftAttribution, LayoutShiftAttribution]
startTime: 11317.934999999125
value: 0.17508567530168798

위의 항목은 세 개의 DOM 요소가 변경되는 동안 레이아웃 변경을 나타냅니다. 있습니다. 이 특정 레이아웃 변경의 레이아웃 변경 점수는 0.175입니다.

다음은 관련성이 가장 높은 LayoutShift 인스턴스의 속성입니다. 레이아웃 변경 디버깅:

속성 설명
sources sources 속성은 레이아웃 변경 중에 이동한 DOM 요소를 나열합니다. 이 배열에는 최대 다섯 개의 소스를 포함할 수 있습니다. 레이아웃 변경의 영향을 받는 요소가 5개 이상인 경우 레이아웃 변경의 가장 큰 요소 5개 (레이아웃 안정성에 대한 영향으로 측정)가 보고됩니다. 이 정보는 LayoutShiftAttribution 인터페이스(아래에 자세히 설명됨)를 사용하여 보고됩니다.
value value 속성은 특정 레이아웃 변경의 레이아웃 변경 점수를 보고합니다.
hadRecentInput hadRecentInput 속성은 사용자 입력 후 500밀리초 이내에 레이아웃 전환이 발생했는지 여부를 나타냅니다.
startTime startTime 속성은 레이아웃 변경 시점을 나타냅니다. startTime는 밀리초로 표시되며 페이지 로드가 시작된 시간을 기준으로 측정됩니다.
duration duration 속성은 항상 0로 설정됩니다. 이 속성은 PerformanceEntry 인터페이스에서 상속됩니다 (LayoutShift 인터페이스는 PerformanceEntry 인터페이스를 확장함). 그러나 기간 개념은 레이아웃 변경 이벤트에 적용되지 않으므로 0로 설정됩니다. PerformanceEntry 인터페이스에 관한 자세한 내용은 사양을 참고하세요.

LayoutShiftAttribution

LayoutShiftAttribution 인터페이스는 단일 DOM 요소의 단일 전환을 설명합니다. 레이아웃 전환 중에 여러 요소가 전환되면 sources 속성에는 여러 항목이 포함됩니다.

예를 들어 아래 JSON은 소스가 하나인 레이아웃 전환(<div id='banner'> DOM 요소가 y: 76에서 y:246로 아래로 전환됨)에 해당합니다.

// ...
  "sources": [
    {
      "node": "div#banner",
      "previousRect": {
        "x": 311,
        "y": 76,
        "width": 4,
        "height": 18,
        "top": 76,
        "right": 315,
        "bottom": 94,
        "left": 311
      },
      "currentRect": {
        "x": 311,
        "y": 246,
        "width": 4,
        "height": 18,
        "top": 246,
        "right": 315,
        "bottom": 264,
        "left": 311
      }
    }
  ]

node 속성은 이동한 HTML 요소를 식별합니다. 마우스를 가져가면 속성은 해당하는 페이지 요소를 강조표시합니다.

previousRectcurrentRect 속성은 노드의 크기와 위치를 보고합니다.

  • xy 좌표는 x 좌표와 y 좌표를 보고합니다. 각 요소의 왼쪽 상단 모서리와
  • widthheight 속성은 요소의 너비와 높이를 각각 보고합니다.
  • top, right, bottom, left 속성은 x 또는 y를 보고합니다. 요소의 지정된 가장자리에 해당하는 좌표 값입니다. 즉, top의 값은 y와 같고 bottom의 값은 y+height와 같습니다.

previousRect의 모든 속성이 0으로 설정되면 요소에 볼 수 있습니다. currentRect의 모든 속성이 0으로 설정되면 확인할 수 있습니다.

이러한 출력을 해석할 때 가장 중요한 점은 소스로 표시된 요소가 레이아웃 전환 중에 이동한 요소라는 것입니다. 하지만 이러한 요소는 '근본 원인'과 관련된 설계할 수 있습니다 다음은 몇 가지 예입니다.

예 1

이러한 레이아웃 변경은 하나의 소스인 요소 B로 보고됩니다. 하지만 이 레이아웃 이동의 근본 원인은 요소 A의 크기 변경입니다.

요소 크기 변경으로 인한 레이아웃 전환을 보여주는 예

예 2

이 예에서 레이아웃 변경은 두 소스, 즉 요소 A와 함께 보고됩니다. 요소 B를 사용할 수 있습니다 이 레이아웃 변경의 근본 원인은 요소 A

요소 위치 변경으로 인한 레이아웃 이동을 보여주는 예시

예 3

이 예에서 레이아웃 변경은 요소 B라는 하나의 소스로 보고됩니다. 요소 B의 위치 변경으로 인해 레이아웃이 변경되었습니다.

요소 위치 변경으로 인한 레이아웃 이동을 보여주는 예시

예 4

요소 B의 크기는 변경되지만 이 예에서는 레이아웃이 변경되지 않습니다.

요소의 크기는 변경되지만 레이아웃 변경을 유발하지 않는 경우를 보여주는 예

Layout Instability API에서 DOM 변경사항이 보고되는 방식을 보여주는 데모를 확인하세요.

DevTools

성능 패널

DevTools 성능 패널의 환경 창에는 특정 성능 트레이스 중에 발생하는 모든 레이아웃 변경사항이 표시됩니다. 이러한 레이아웃 변경사항은 사용자 상호작용 후 500밀리초 이내에 발생하더라도 CLS에 반영되지 않습니다. 환경 패널에서 특정 레이아웃 변경 위로 마우스를 가져가면 영향을 받은 DOM 요소가 강조 표시됩니다.

DevTools Network 패널에 표시된 레이아웃 변경의 스크린샷

레이아웃 이동에 관한 자세한 내용을 보려면 레이아웃 이동을 클릭한 다음 요약 창을 엽니다. 요소의 크기 변경사항이 나열됩니다. [width, height] 형식 사용 요소의 위치 변경사항이 나열됨 [x,y] 형식 사용. 최근 입력 있음 속성은 사용자 상호작용 후 500ms 이내에 레이아웃 변경이 발생했습니다.

DevTools &#39;Summary&#39; 스크린샷 레이아웃 변경 탭

레이아웃 변경 기간에 대한 자세한 내용은 이벤트 로그 탭을 엽니다. 환경 창에서 빨간색 레이아웃 전환 직사각형의 길이를 확인하여 레이아웃 전환 시간을 대략적으로 추정할 수도 있습니다.

DevTools &#39;Event Log&#39; 스크린샷 레이아웃 변경 탭

성능 패널 사용에 관한 자세한 내용은 성능 분석 참조를 참고하세요.

레이아웃 변경 지역 강조 표시

레이아웃 변경 영역을 강조 표시하면 페이지에서 발생하는 레이아웃 변경의 위치와 시점을 한눈에 파악하는 데 도움이 됩니다.

DevTools에서 Layout Shift Regions를 사용 설정하려면 Settings > More Tools > Rendering > Layout Shift Regions로 이동한 다음 디버그하려는 페이지를 새로고침합니다. 레이아웃 변경 영역이 잠시 보라색으로 강조 표시됩니다.

레이아웃 변경의 원인을 식별하기 위한 사고 프로세스

아래 단계에 따라 레이아웃 전환이 발생하는 시점이나 방식과 관계없이 레이아웃 전환의 원인을 파악할 수 있습니다. 이러한 단계는 Lighthouse를 실행하여 보완할 수 있습니다. 단, Lighthouse는 초기 페이지 로드 중에 발생한 레이아웃 전환만 식별할 수 있습니다. 또한 Lighthouse는 레이아웃 전환의 일부 원인(예: 명시적인 너비와 높이가 없는 이미지 요소)에 대해서만 제안을 제공할 수 있습니다.

레이아웃 변경의 원인 파악

레이아웃 변경은 다음과 같은 이벤트로 인해 발생할 수 있습니다.

  • DOM 요소의 위치 변경
  • DOM 요소의 크기 변경사항
  • DOM 요소 삽입 또는 제거
  • 레이아웃을 트리거하는 애니메이션

특히, 변경된 요소 바로 앞에 오는 DOM 요소는 '원인'과 관련될 가능성이 가장 높은 요소 있습니다. 따라서 레이아웃 변경이 발생한 이유를 조사하는 경우 다음을 고려하세요.

  • 이전 요소의 위치 또는 크기가 변경되었나요?
  • DOM 요소가 이동한 요소보다 먼저 삽입되거나 삭제되었나요?
  • 이동한 요소의 위치가 명시적으로 변경되었나요?

앞의 요소로 인해 레이아웃이 바뀌지 않았다면 다음과 같이 검색을 계속합니다. 다른 선행 요소와 주변 요소를 고려합니다.

또한 레이아웃 변경의 방향과 거리는 힌트를 제공할 수 있습니다. 살펴봤습니다 예를 들어 하향 변동이 크다는 것은 대개 일반적으로 1픽셀 또는 2픽셀 레이아웃 변경은 충돌하는 CSS 스타일을 적용하거나 웹 글꼴입니다.

글꼴 교체로 인한 레이아웃 전환을 보여주는 다이어그램
이 예에서는 글꼴을 전환하면 페이지 요소가 위쪽으로 5픽셀 이동했습니다.

다음은 레이아웃 변경을 가장 자주 유발하는 특정 동작입니다. 이벤트:

요소의 위치 변경 (다른 요소의 이동으로 인한 것이 아닌 경우)

이러한 유형의 변경사항은 다음과 같은 이유로 인해 발생하는 경우가 많습니다.

  • 늦게 로드되거나 이전에 선언된 스타일을 덮어쓰는 스타일시트
  • 애니메이션 및 전환 효과

요소의 크기 변경

이러한 유형의 변경사항은 다음과 같은 이유로 인해 발생하는 경우가 많습니다.

  • 늦게 로드되거나 이전에 선언된 스타일을 덮어쓰는 스타일시트
  • '슬롯'이 렌더링된 후에 로드되는 widthheight 속성이 없는 이미지 및 iframe
  • width 또는 height 속성이 없는 텍스트 블록은 텍스트가 렌더링됩니다.

DOM 요소 삽입 또는 삭제

이러한 현상은 주로 다음과 같은 이유로 발생합니다.

  • 광고 및 기타 서드 파티 삽입 삽입
  • 배너, 알림, 모달 삽입
  • 기존 콘텐츠 위에 추가 콘텐츠를 로드하는 무한 스크롤 및 기타 UX 패턴

레이아웃을 트리거하는 애니메이션

일부 애니메이션 효과는 레이아웃을 트리거할 수 있습니다. 이러한 일반적인 예는 CSS의 transform 속성을 사용하는 대신 top 또는 left와 같은 속성을 증분하여 DOM 요소에 '애니메이션'을 적용하는 경우입니다. 고성능 CSS 애니메이션을 만드는 방법 읽기 를 참조하세요.

레이아웃 변경 재현

재현할 수 없는 레이아웃 이동은 수정할 수 없습니다. 가장 간단하면서도 사이트 레이아웃을 제대로 파악하기 위해 할 수 있는 가장 효과적인 작업 목표 달성을 위해 사이트와 상호작용하는 데 5~10분이 소요됨 레이아웃 변경을 트리거합니다. 이 작업을 하는 동안 콘솔을 열어 두고 Layout Instability API를 사용하여 레이아웃 이동을 보고합니다.

레이아웃 전환을 찾기 어려운 경우 다른 기기와 연결 속도로 이 연습을 반복해 보세요. 특히 더 느린 지연 시간을 레이아웃 변경을 더 쉽게 파악할 수 있습니다. 또한 debugger 문을 사용하여 레이아웃 전환을 더 쉽게 단계별로 살펴볼 수 있습니다.

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      debugger;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

마지막으로, 개발 시 재현할 수 없는 레이아웃 문제의 경우 다음을 고려하세요. 프런트엔드 로깅 도구와 함께 Layout Instability API 사용 이러한 문제에 대한 추가 정보를 수집할 수 있습니다. 결제 페이지에서 가장 크게 변경된 요소를 추적하는 방법에 대한 예제 코드를 참조하세요.