렌더링 트리 생성, 레이아웃 및 페인트

Ilya Grigorik
Ilya Grigorik

게시일: 2014년 3월 31일

CSSOM 및 DOM 트리는 결합하여 렌더링 트리를 형성합니다. 이 렌더링 트리는 표시되는 각 요소의 레이아웃을 계산하는 데 사용되고 픽셀을 화면에 렌더링하는 페인트 프로세스에 대한 입력으로 처리됩니다. 최적의 렌더링 성능을 얻기 위해서는 이러한 각 단계를 최적화하는 것이 중요합니다.

객체 모델을 생성하는 방법을 설명한 이전 섹션에서 우리는 HTML 및 CSS 입력을 기반으로 DOM 및 CSSOM 트리를 빌드했습니다. 하지만, 이들 모두 문서의 각기 다른 측면을 캡처하는 서로 독립적인 객체입니다. 하나는 콘텐츠를 설명하고, 다른 하나는 문서에 적용되어야 하는 스타일 규칙을 설명합니다. 이 두 가지를 병합하여 브라우저가 화면에 픽셀을 렌더링하도록 하려면 어떻게 해야 할까요?

  • DOM 및 CSSOM 트리는 결합되어 렌더링 트리를 형성합니다.
  • 렌더링 트리에는 페이지를 렌더링하는 데 필요한 노드만 포함됩니다.
  • 레이아웃은 각 객체의 정확한 위치 및 크기를 계산합니다.
  • 마지막 단계는 최종 렌더링 트리에서 수행되는 페인트이며, 픽셀을 화면에 렌더링합니다.

먼저, 브라우저가 DOM 및 CSSOM을 '렌더링 트리'에 결합합니다. 이 트리는 페이지에 표시되는 모든 DOM 콘텐츠와 각 노드에 대한 모든 CSSOM 스타일 정보를 캡처합니다.

DOM 및 CSSOM은 결합되어 렌더링 트리를 생성합니다.

렌더링 트리를 생성하려면 브라우저가 대략적으로 다음 작업을 수행합니다.

  1. DOM 트리의 루트에서 시작하여 표시되는 노드 각각을 트래버스합니다.

    • 일부 노드는 표시되지 않으며(예: 스크립트 태그, 메타 태그 등), 렌더링된 출력에 반영되지 않으므로 생략됩니다.
    • 일부 노드는 CSS를 사용하여 숨겨지며 렌더링 트리에서도 생략됩니다. 예를 들어 위의 예에서 span 노드는 'display: none' 속성을 설정하는 명시적 규칙이 있기 때문에 렌더링 트리에서 누락됩니다.
  2. 표시된 각 노드에 대해 적절하게 일치하는 CSSOM 규칙을 찾아 적용합니다.

  3. 표시된 노드를 콘텐츠 및 계산된 스타일과 함께 내보냅니다.

최종 출력은 화면에 표시되는 모든 노드의 콘텐츠 및 스타일 정보를 모두 포함하는 렌더링 트리입니다. 렌더링 트리가 생성되었으므로 '레이아웃' 단계로 진행할 수 있습니다.

지금까지 표시할 노드와 해당 노드의 계산된 스타일을 계산했습니다. 하지만 기기의 뷰포트 내에서 이러한 노드의 정확한 위치와 크기를 계산하지는 않았습니다. 이것이 바로 '레이아웃' 단계이며, 경우에 따라 '리플로우'라고도 합니다.

페이지에서 각 객체의 정확한 크기와 위치를 파악하기 위해 브라우저는 렌더링 트리의 루트에서 시작하여 렌더링 트리를 통과합니다. 다음 예를 살펴보세요.

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>Critial Path: Hello world!</title>
  </head>
  <body>
    <div style="width: 50%">
      <div style="width: 50%">Hello world!</div>
    </div>
  </body>
</html>

직접 해 보기

이전 예의 <body>에는 중첩된 두 개의 <div>가 포함되어 있습니다. 첫 번째(상위) <div>는 노드의 표시 크기를 뷰포트 너비의 50%로 설정하고, 상위에 포함된 두 번째 <div>width를 상위의 50%(즉, 뷰포트 너비의 25%)로 설정합니다.

레이아웃 정보 계산 중

레이아웃 프로세스에서는 뷰포트 내에서 각 요소의 정확한 위치와 크기를 정확하게 캡처하는 '상자 모델'이 출력됩니다. 모든 상대적인 측정값은 화면에서 절대적인 픽셀로 변환됩니다.

마지막으로, 이제 표시되는 노드와 해당 노드의 계산된 스타일 및 기하학적 형태에 대해 파악했으므로, 렌더링 트리의 각 노드를 화면의 실제 픽셀로 변환하는 마지막 단계로 이러한 정보를 전달할 수 있습니다. 이 단계를 흔히 '페인팅' 또는 '래스터화'라고 합니다.

이 경우 브라우저가 처리해야 할 작업이 상당히 많으므로 시간이 약간 걸릴 수 있습니다. 그러나 Chrome DevTools는 이전에 설명된 세 단계 모두에 대해 몇 가지 정보를 제공할 수 있습니다. 원래 'Hello World' 예시의 레이아웃 단계를 살펴보겠습니다.

DevTools에서 레이아웃 측정

  • 'Layout' 이벤트는 타임라인에서 렌더링 트리 생성, 위치, 크기 계산을 캡처합니다.
  • 레이아웃이 완료되면 브라우저가 'Paint Setup' 및 'Paint' 이벤트를 발생시킵니다. 이러한 작업은 렌더링 트리를 화면의 픽셀로 변환합니다.

렌더링 트리 생성, 레이아웃, 페인트를 실행하는 데 필요한 시간은 문서 크기, 적용된 스타일, 실행 중인 기기에 따라 다릅니다. 문서가 클수록 브라우저에서 더 많은 작업을 실행해야 합니다. 스타일이 복잡할수록 페인팅하는 데 더 많은 시간이 걸립니다(예: 단색은 페인트하기 '저렴'하지만 음영은 계산 및 렌더링하기 '비싸').

페이지가 드디어 뷰포트에 표시됩니다.

렌더링된 Hello World 페이지

다음은 브라우저의 단계를 간략히 요약한 것입니다.

  1. HTML 마크업을 처리하고 DOM 트리를 빌드합니다.
  2. CSS 마크업을 처리하고 CSSOM 트리를 빌드합니다.
  3. DOM 및 CSSOM을 결합하여 렌더링 트리를 만듭니다.
  4. 렌더링 트리에서 레이아웃을 실행하여 각 노드의 기하학적 형태를 계산합니다.
  5. 개별 노드를 화면에 페인트합니다.

데모 페이지는 평범해 보일 수 있지만 브라우저 측에서 상당한 작업을 수행해야 합니다. DOM 또는 CSSOM이 수정된 경우 화면에서 다시 렌더링해야 할 픽셀을 파악하려면 이 프로세스를 반복해야 합니다.

주요 렌더링 경로를 최적화하는 작업은 위 단계에서 1단계~5단계를 수행할 때 걸린 총 시간을 최소화하는 프로세스입니다. 이렇게 하면 콘텐츠를 가능한 한 빨리 화면에 렌더링할 수 있으며, 초기 렌더링 후 화면 업데이트 사이의 시간을 줄여 줍니다. 따라서 대화형 콘텐츠의 새로고침 속도를 높일 수 있습니다.

의견