- Today
- Total
빵 입니다.
Render Tree 구성, Reflow, Paint(Repaint) 본문
CSSOM tree와 DOM tree는 Render tree로 결합된다. Render tree는 표시되는 각 요소들의 “레이아웃”을 계산하는 데 사용되며, 각 노드를 화면의 실제 픽셀로 렌더링하는 페인트 프로세스에서 사용하는 입력값으로 사용된다.
HTML, CSS 입력값을 기반으로 DOM tree와 CSSOM tree를 만들었다. 그러나 둘 다 document의 다른 측면을 캡처하는 독립적인 객체이다. 하나는 콘텐츠에 대한 설명이고, 하나는 document에 적용해야하는 스타일 규칙에 대한 설명이다.
어떻게 두가지를 병합하고, 브라우저가 화면의 픽셀을 렌더링하도록 할까?
📌 TL;DR
- DOM tree와 CSSOM tree가 결합되어 Render tree를 만든다.
- Render tree는 화면을 렌더링하는 데 필요한 노드들만 포함한다.
- 각 객체의 정확한 위치와 크기를 계산하는 “레이아웃”을 실행한다. (= 리플로우)
- 최종 Render tree를 가져와 픽셀을 화면에 렌더링하는 “페인트” 실행한다. (=래스터화)
📌 1. DOM tree와 CSSOM tree 결합되어 Render tree 만든다.
먼저 브라우저는 DOM과 CSSOM를 결합되어 페이지에 표시되는 모든 DOM 콘텐츠와 각 노드의 스타일 정보를 캡처하는 Render tree를 만든다.
1. HTML 마크업을 처리하고 DOM tree 빌드
- Root DOM trr에서 시작해서 보이는 각각의 요소들을 순회한다.
- script 태그나 meta 태그 같은 것들은 표시되지 않는 요소들이고, 렌더링된 output에 반영되지 않으므로 생략된다.
- CSS를 통해 감춰진 요소들도 Render tree에서 생략된다.
=> 명시된 규칙에의 해 * display: none; 처리된 span 요소는 Render tree에서 찾을 수 없다.
2. CSS 스타일링 처리하고 CSSOM tree 빌드
표시되는 각각의 노드에 대해 적절하게 일치하는 CSSON 규칙을 찾아 적용한다.
3. DOM tree와 CSSOM tree 결합되어 Render tree 만든다.
콘텐츠와 계산된 스타일이 있는 표시되는 노드들을 보여준다.
* visibility: hidden과 display: none은 다르다. visibility: hidden은 보이지 않게 만들지만, 요소는 여전히 레이아웃에서 공간을 차지한다. display: none은 요소가 보이지 않고, 표시되지 않도록 렌더링 트리에서 요소를 완전히 제거한다.
최종 output은 콘텐츠와 화면에 표시되는 모든 콘텐츠의 스타일 정보를 모두 포함하는 렌더링이다.
Render tree가 준비되면 “layout” 단계를 진행할 수 있다.
📌 2. 각 객체의 정확한 위치와 크기를 계산하는 “레이아웃”을 실행한다. (= 리플로우)
지금까지 우리는 표시되어야 하는 노드와 계산된 스타일을 계산했다.
그러나 디바이스의 뷰포트 내에서 정확한 위치와 크기를 계산하진 않았다.
이것이 “Reflow”라고 하는 “Layout” 단계이다.
페이지에서 각 객체의 정확한 위치와 크기를 파악하려면, 브라우저는 Render tree의 Root에서 시작해서 객체를 탐색해야 한다.
<!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는 2개의 div를 가지고 있다. 첫번째 div(부모)는 요소의 표시 크기를 뷰포트 넓이의 50%로 설정했고, 두번째 div는 첫번째 div(부모)의 50%의 넓이로 설정했다. 즉 뷰포트 넓이의 25%로 설정했다.
“레이아웃” 프로세스의 output은 뷰포트 내에서 각 요소의 정확한 위치와 크기를 정확하게 캡쳐하는 박스 모델이다.
모든 상대 측정은 화면 상에 절대 pixel 값으로 변환된다.
📌 3. 최종 Render tree를 가져와 픽셀을 화면에 렌더링하는 “페인트” 실행한다. (=래스터화)
마지막으로 이제 우리는 어떤 노드가 표시되는지, 각 노드들의 계산된 스타일과 기하학을 알고 있다.
이 정보를 Render tree의 각 노드를 화면의 실제 픽셀로 변환하는 최종 단계로 전달할 수 있다.
이 단계를 종종 “Paint” 또는 “Rasterize”라고 한다.
(입력값이 발생해 화면을 다시 그릴 경우 "Repaint"라고 한다.)
이 과정은 브라우저가 꽤 많은 작업을 수행해야 하기 때문에 시간이 좀 걸릴 수도 있다.
그러나 Chrome DevTools는 위에서 설명한 세 단계 모두에 대한 insight를 제공한다. (시각적으로 볼 수 있는…)
“Hello world”로 테스트를 해본다면…
- “레이아웃” 이벤트는 Timeline에 Render tree 생성, 위치, 사이즈 계산을 캡처한다.
- “레이아웃”이 완료되면 브라우저는 Render tree를 화면의 픽셀로 변환하는 “Paint setup”, “Paint” 이벤트를 발생시킨다.
📌 결론
Render tree 생성, layout, paint를 실행하는데 필요한 시간은 document의 크기, 적용된 스타인, 실행 중인 디바이스의 스펙에 따라 다르다.
document의 크기가 클수록 브라우저가 해야할 작업이 더 많다.
스타일이 더 복잡할수록 paint하는데 시간도 더 걸린다.
(ex. solid 색상은 paint 하는데 저렴한 비용이 들고, drop shadow는 계산, 렌더링 하는데 더 비싸다.)
위 과정을 모두 진행하고 나면, 드디어 화면이 표시된다.
📌 브라우저의 단계별 작업 요약
1. HTML 마크업을 처리하고 DOM tree 빌드
2. CSS 스타일링 처리하고 CSSOM tree 빌드
3. DOM tree와 CSSOM tree 결합되어 Render tree 만든다.
4. Render tree에서 “레이아웃 = 리플로우" 실행하여 각 노드의 geometry 계산
5. 화면에 개별 노드 “리페인트 = 래스터화” 실행하여 그리기
* 화면이 단순해 보이지만,
DOM, CSSOM이 수정된 경우, 화면에 다시 렌더링해야 하는 픽셀을 파악하기 위해 프로세스를 반복해야 한다.
중요한 렌더링 경로 최적화하는 것은 위의 1~5단계를 수행하는데 걸리는 시간의 총 양을 최소화 하는 프로세스이다.
이렇게 하면 콘텐츠가 가능한 한 빨리 화면에 렌더링되고, 초기 렌더링 후 화면 업데이트 사이에 걸리는 시간의 양을 줄일 수 있다.
🫰🏻 참고 🫰🏻
https://web.dev/critical-rendering-path-render-tree-construction/
'브라우저' 카테고리의 다른 글
Object Model 구성 (0) | 2022.07.26 |
---|