큰 DOM 크기가 상호작용에 미치는 영향과 이에 대해 취할 수 있는 조치

DOM 크기가 크면 생각보다 상호작용에 큰 영향을 미칩니다. 이 가이드에서는 그 이유와 해결 방법을 설명합니다.

방법은 없습니다. 웹페이지를 만들면 해당 페이지에는 문서 객체 모델 (DOM)이 생깁니다. DOM은 페이지의 HTML 구조를 나타내며, 페이지의 구조와 콘텐츠에 대한 액세스 권한을 JavaScript 및 CSS에 제공합니다.

하지만 문제는 DOM의 크기가 페이지를 빠르고 효율적으로 렌더링하는 브라우저의 기능에 영향을 미친다는 것입니다. 일반적으로 DOM이 클수록 처음에 페이지를 렌더링하고 페이지 수명 주기에서 렌더링을 업데이트하는 데 더 많은 비용이 소요됩니다.

DOM이 매우 큰 페이지에서 DOM을 수정하거나 업데이트하는 상호작용이 페이지의 빠른 응답 기능에 영향을 주는 값비싼 레이아웃 작업을 트리거하는 경우 문제가 됩니다. 고비용 레이아웃 작업은 페이지의 Interaction to Next Paint (INP)에 영향을 줄 수 있습니다. 페이지가 사용자 상호작용에 빠르게 반응하도록 하려면 DOM 크기가 필요한 만큼만 커야 합니다.

페이지의 DOM이 너무 큰 경우는 언제인가요?

Lighthouse에 따르면 페이지의 DOM 크기가 노드 1,400개를 초과하면 페이지의 DOM 크기가 과도하다고 합니다. Lighthouse는 페이지의 DOM이 800개의 노드를 초과하면 경고를 생성하기 시작합니다. 다음 HTML을 예로 들어 보겠습니다.

<ul>
  <li>List item one.</li>
  <li>List item two.</li>
  <li>List item three.</li>
</ul>

위 코드에는 4개의 DOM 요소, 즉 <ul> 요소와 이 요소의 <li> 하위 요소 3개가 있습니다. 웹페이지에는 이보다 더 많은 노드가 있을 것이 거의 확실합니다. 따라서 DOM 크기를 유지하기 위해 할 수 있는 작업과 페이지의 DOM을 가능한 한 작게 했을 때 렌더링 작업을 최적화하기 위한 기타 전략을 이해하는 것이 중요합니다.

큰 DOM은 페이지 성능에 어떤 영향을 주나요?

큰 DOM은 몇 가지 방식으로 페이지 성능에 영향을 미칩니다.

  1. 페이지의 초기 렌더링 중 CSS가 페이지에 적용되면 DOM과 유사한 구조인 CSSOM (CSS 객체 모델)이 생성됩니다. CSS 선택자의 구체성이 높아짐에 따라 CSSOM은 더욱 복잡해지고, 웹페이지를 화면에 그리는 데 필요한 레이아웃, 스타일 지정, 합성, 페인트 작업을 실행하는 데 더 많은 시간이 필요합니다. 이러한 추가 작업은 페이지 로드 도중에 초기에 발생하는 상호작용의 상호작용 지연 시간을 증가시킵니다.
  2. 상호작용이 요소 삽입 또는 삭제를 통해 또는 DOM 콘텐츠와 스타일을 수정하여 DOM을 수정하는 경우, 해당 업데이트를 렌더링하는 데 필요한 작업으로 인해 레이아웃, 스타일 지정, 합성, 페인트 작업이 매우 큰 비용이 들 수 있습니다. 페이지의 초기 렌더링과 마찬가지로, HTML 요소가 상호작용의 결과로 DOM에 삽입될 때 CSS 선택자 특정성이 증가하면 렌더링 작업이 더 좋아질 수 있습니다.
  3. JavaScript가 DOM을 쿼리할 때 DOM 요소에 대한 참조가 메모리에 저장됩니다. 예를 들어 document.querySelectorAll를 호출하여 페이지의 모든 <div> 요소를 선택하는 경우, 결과가 많은 수의 DOM 요소를 반환하는 경우 메모리 비용이 상당히 높을 수 있습니다.
Chrome DevTools의 성능 패널에서 과도한 렌더링 작업으로 인해 발생한 긴 작업의 스크린샷 긴 작업의 호출 스택은 페이지 스타일을 다시 계산하고 미리 페인트를 하는 데 소비된 상당한 시간을 보여줍니다.
Chrome DevTools의 성능 프로파일러에 표시된 긴 작업 표시되는 긴 작업은 자바스크립트를 통해 큰 DOM에 DOM 요소를 삽입할 때 발생합니다.

이 모든 것이 상호작용에 영향을 줄 수 있지만 위 목록의 두 번째 항목이 특히 중요합니다. 상호작용으로 인해 DOM이 변경되면 페이지에서 잘못된 INP를 초래하는 많은 작업이 시작될 수 있습니다.

DOM 크기는 어떻게 측정하나요?

DOM 크기는 두 가지 방법으로 측정할 수 있습니다. 첫 번째 방법은 Lighthouse를 사용합니다. 감사를 실행할 때 현재 페이지의 DOM 관련 통계는 '과도한 DOM 크기 방지하기'에 있습니다. '진단' 섹션에 있는 있습니다. 이 섹션에서는 DOM 요소의 총 개수, 가장 많은 하위 요소가 포함된 DOM 요소 및 가장 깊은 DOM 요소를 확인할 수 있습니다.

간단한 방법은 모든 주요 브라우저의 개발자 도구에서 JavaScript 콘솔을 사용하는 것입니다. DOM에 있는 총 HTML 요소의 수를 가져오려면 페이지가 로드된 후 콘솔에서 다음 코드를 사용하면 됩니다.

document.querySelectorAll('*').length;

DOM 크기 업데이트를 실시간으로 확인하려면 실적 모니터링 도구를 사용하면 됩니다. 이 도구를 사용하면 레이아웃과 스타일 지정 작업 (및 기타 성능 측면)을 현재 DOM 크기와 함께 연결할 수 있습니다.

<ph type="x-smartling-placeholder">
</ph> Chrome DevTools의 성능 모니터 스크린샷 왼쪽에는 페이지의 수명 기간 동안 지속적으로 모니터링할 수 있는 페이지 성능의 다양한 측면이 있습니다. 이 스크린샷에서는 DOM 노드 수, 초당 레이아웃, 섹션당 스타일 재계산이 활발하게 모니터링되고 있습니다. <ph type="x-smartling-placeholder">
</ph> Chrome DevTools의 성능 모니터 이 보기에서는 페이지의 현재 DOM 노드 수가 초당 레이아웃 작업 및 스타일 재계산과 함께 차트로 표시됩니다.

DOM의 크기가 Lighthouse DOM 크기의 경고 임계값에 가까워지거나 모두 실패하는 경우, 다음 단계는 웹사이트의 INP를 개선할 수 있도록 DOM의 크기를 줄여 사용자 상호작용에 대한 페이지의 기능을 개선하는 방법을 파악하는 것입니다.

상호작용의 영향을 받는 DOM 요소의 수를 어떻게 측정할 수 있나요?

실험실에서 느린 상호작용을 프로파일링하는 경우 페이지의 DOM 크기와 관련이 있을 수 있다고 생각되는 경우, 프로파일러에서 'ReCalculate Style'이라는 라벨이 지정된 액티비티를 선택하여 얼마나 많은 DOM 요소가 영향을 받았는지 파악할 수 있습니다. 하단 패널의 문맥 데이터를 관찰합니다.

<ph type="x-smartling-placeholder">
</ph> Chrome DevTools의 성능 패널에서 선택한 스타일 재계산 활동의 스크린샷. 상호작용 트랙에는 클릭 상호작용이 표시되며 대부분의 작업은 스타일 재계산과 사전 페인트 작업에 사용됩니다. 하단의 패널에는 선택한 활동에 대한 자세한 내용이 표시되며, 이 패널에는 2,547개의 DOM 요소가 영향을 받았음을 보고합니다. <ph type="x-smartling-placeholder">
</ph> 스타일 재계산 작업의 결과로 DOM에서 영향을 받는 요소의 수를 관찰합니다. 상호작용 트랙에서 음영 처리된 부분은 상호작용 시간 중 200밀리초가 넘는 부분('양호'로 지정된 부분)을 INP 기준점을 참고하세요.

위 스크린샷에서 작업의 스타일 재계산을 선택하면 영향을 받는 요소의 수가 표시됩니다. 위의 스크린샷은 많은 DOM 요소가 있는 페이지에서 DOM 크기가 렌더링 작업의 영향을 미치는 극단적인 사례를 보여주지만, 이 진단 정보는 어떤 경우든 DOM의 크기가 상호작용에 대한 응답으로 다음 프레임이 페인트하는 데 걸리는 시간을 제한 요소인지 결정하는 데 유용합니다.

DOM 크기를 줄이려면 어떻게 해야 하나요?

웹사이트의 HTML에 불필요한 마크업이 있는지 감사하는 것 외에도 DOM 크기를 줄이는 주요 방법은 DOM 깊이를 줄이는 것입니다. DOM이 불필요하게 깊은 경우의 신호 중 하나는 브라우저 개발자 도구의 Elements 탭에 다음과 같은 마크업이 표시되는 경우입니다.

<div>
  <div>
    <div>
      <div>
        <!-- Contents -->
      </div>
    </div>
  </div>
</div>

이와 같은 패턴이 보이면 DOM 구조를 평면화하여 패턴을 단순화할 수 있습니다. 이렇게 하면 DOM 요소의 수가 줄어들고 페이지 스타일을 단순화할 수 있습니다.

DOM 깊이는 사용하는 프레임워크의 징후일 수도 있습니다. 특히 구성요소 기반 프레임워크(예: JSX에 의존하는 프레임워크)의 경우 상위 컨테이너에 여러 구성요소를 중첩해야 합니다.

그러나 많은 프레임워크에서 프래그먼트라고 하는 것을 사용하여 구성요소를 중첩하지 않도록 할 수 있습니다. 프래그먼트를 기능으로 제공하는 구성요소 기반 프레임워크에는 다음이 포함되나 이에 국한되지 않습니다.

선택한 프레임워크에서 프래그먼트를 사용하여 DOM 깊이를 줄일 수 있습니다. DOM 구조 평면화가 스타일 지정에 미치는 영향이 우려되는 경우 flexbox 또는 그리드와 같은 더 현대적이고 빠른 레이아웃 모드를 사용하는 것이 좋습니다.

기타 고려할 만한 전략

DOM을 최대한 작게 유지하기 위해 DOM 트리를 평면화하고 불필요한 HTML 요소를 제거하더라도 여전히 상당히 클 수 있으며 사용자 상호작용에 반응하여 많은 렌더링 작업을 시작할 수 있습니다. 이러한 상황에 처한 경우 렌더링 작업을 제한하기 위해 고려할 수 있는 다른 전략이 있습니다.

가산적 접근 방식 고려

페이지가 처음 렌더링될 때 처음에는 페이지의 많은 부분이 사용자에게 표시되지 않을 수 있습니다. 시작 시 DOM의 해당 부분을 생략하여 HTML을 지연 로드할 기회가 될 수 있지만, 사용자가 페이지의 초기에 숨겨진 측면이 필요한 페이지 부분과 상호작용할 때 이를 추가할 수 있습니다.

이 접근 방식은 초기 로드 도중은 물론 로드 후에도 유용합니다. 초기 페이지 로드의 경우 미리 렌더링 작업을 적게 해야 합니다. 즉, 초기 HTML 페이로드는 더 가벼워지고 렌더링 속도도 빨라집니다. 이렇게 하면 이 중요한 기간 동안 기본 스레드의 주의를 끌기 위한 경쟁을 줄이면서 상호작용을 실행할 수 있는 기회가 더 많아집니다.

로드 시 처음에는 페이지의 많은 부분이 숨겨지면 재렌더링 작업을 트리거하는 다른 상호작용의 속도도 빨라질 수 있습니다. 그러나 다른 상호작용이 DOM에 더 추가되면 페이지 수명 주기 동안 DOM이 확장됨에 따라 렌더링 작업도 증가합니다.

시간이 지남에 따라 DOM에 추가하는 것은 까다로울 수 있으며 고유한 장단점이 있습니다. 이 방법을 사용할 경우 사용자 상호작용에 대한 응답으로 페이지에 추가하려는 HTML을 채우기 위해 데이터를 가져오기 위해 네트워크 요청을 할 가능성이 높습니다. 이동 중인 네트워크 요청은 INP에 포함되지 않지만 인지되는 지연 시간은 늘어날 수 있습니다. 가능하면 데이터를 가져오는 중임을 나타내는 로드 스피너 또는 기타 표시기를 표시하여 사용자가 상황을 파악할 수 있도록 하세요.

CSS 선택자 복잡성 제한

브라우저가 CSS에서 선택자를 파싱할 때 DOM 트리를 순회하여 이러한 선택자가 현재 레이아웃에 적용되는지, 적용되는지 파악해야 합니다. 이러한 선택자가 더 복잡할수록 페이지의 초기 렌더링은 물론 상호작용의 결과로 페이지가 변경될 경우 향상된 스타일 재계산 및 레이아웃 작업을 모두 수행하기 위해 브라우저가 더 많은 작업을 실행해야 합니다.

content-visibility 속성 사용

CSS는 화면 밖의 DOM 요소를 효과적으로 지연 렌더링하는 content-visibility 속성을 제공합니다. 요소가 표시 영역에 가까워지면 요청 시 렌더링됩니다. content-visibility의 이점은 초기 페이지 렌더링에서 상당한 양의 렌더링 작업을 줄일 뿐 아니라 사용자 상호작용의 결과로 페이지 DOM이 변경될 때 화면 밖 요소의 렌더링 작업을 건너뜁니다.

결론

웹사이트의 INP를 최적화하는 좋은 방법은 DOM 크기를 꼭 필요한 정도로만 줄이는 것입니다. 이렇게 하면 DOM이 업데이트될 때 브라우저가 레이아웃 및 렌더링 작업을 수행하는 데 걸리는 시간을 줄일 수 있습니다. DOM 크기를 유의미하게 줄일 수 없더라도 렌더링 작업을 DOM 하위 트리로 격리하는 데 사용할 수 있는 몇 가지 기법이 있습니다(예: CSS 포함 및 content-visibility CSS 속성).

어떤 방법을 사용하든 렌더링 작업을 최소화하는 환경을 만들고 상호작용에 대한 페이지의 렌더링 작업량을 줄여 사용자가 상호작용할 때 웹사이트가 더 반응하는 느낌을 받을 수 있습니다. 즉, 웹사이트의 INP가 낮아져 사용자 환경이 개선됩니다.

루이스 리드Unsplash의 히어로 이미지