브라우저는 HTML을 어떻게 화면에 그릴까?
Article
퍼블리셔라면 HTML과 CSS를 매일 다룹니다. 그런데 브라우저가 이 코드를 받아서 실제로 화면에 그리기까지 어떤 일이 벌어지는지 생각해본 적 있나요?
이 과정을 이해하면 나중에 React의 가상 DOM이 왜 필요한지가 자연스럽게 이해됩니다. 그 출발점이 되는 이야기입니다.
HTML을 받으면 가장 먼저 하는 일
브라우저는 HTML 파일을 받으면 위에서 아래로 한 줄씩 읽어 내려갑니다. 그리고 이걸 DOM 트리라는 구조로 바꿉니다.
DOM은 Document Object Model의 약자인데, 쉽게 말하면 HTML 태그들의 가계도입니다.
<html>
<body>
<h1>안녕하세요</h1>
<p>반갑습니다</p>
</body>
</html>
이 코드를 브라우저가 읽으면 이런 트리가 만들어집니다.
html
└── body
├── h1 → "안녕하세요"
└── p → "반갑습니다"
부모-자식 관계가 있는 나무 구조입니다. 퍼블리셔에게 익숙한 태그 중첩 구조 그 자체가 DOM 트리입니다.
CSS도 트리가 됩니다
HTML이 DOM 트리가 되는 것처럼, CSS도 CSSOM 트리로 변환됩니다.
CSSOM은 CSS Object Model의 약자입니다. 브라우저는 CSS 파일을 읽으면서 "이 선택자에 이 스타일이 적용된다"는 정보를 트리 구조로 정리합니다.
예를 들어 body { font-size: 16px; } 아래에 h1 { color: red; }가 있으면, h1은 body의 font-size를 상속받으면서 자기만의 color도 갖게 됩니다. 이런 상속과 우선순위 계산이 CSSOM에서 일어납니다.
두 트리를 합칩니다 — 렌더 트리
DOM 트리와 CSSOM 트리가 준비되면, 브라우저는 이 둘을 합쳐서 렌더 트리를 만듭니다.
렌더 트리는 실제로 화면에 보이는 것들만 포함합니다. display: none이 적용된 요소는 여기서 빠집니다. <head> 태그 안의 내용도 빠집니다. 오직 눈에 보이는 요소와 그에 적용된 스타일만 남습니다.
비유하자면, DOM 트리가 건물의 전체 설계도라면 렌더 트리는 실제로 지을 부분만 표시한 시공 도면입니다.
레이아웃 — 어디에 얼마나 크게?
렌더 트리가 완성되면 브라우저는 레이아웃 단계에 들어갑니다. 이걸 리플로우(Reflow) 라고도 부릅니다.
이 단계에서 브라우저는 각 요소의 정확한 위치와 크기를 계산합니다. "이 div는 왼쪽에서 100px, 위에서 200px 위치에 너비 300px, 높이 150px"처럼 구체적인 좌표를 잡는 겁니다.
width가 50%라면 부모 요소의 크기를 기준으로 실제 픽셀값을 계산합니다. margin: auto도 이 단계에서 실제 수치로 바뀝니다.
페인트 — 드디어 그립니다
위치와 크기가 정해지면 마지막으로 페인트(Paint) 단계가 옵니다. 실제로 픽셀을 화면에 찍는 단계입니다.
배경색, 텍스트, 테두리, 그림자 같은 시각적 요소들이 이때 그려집니다.
전체 흐름 정리
HTML → DOM 트리
CSS → CSSOM 트리
↓
렌더 트리
↓
레이아웃(리플로우) — 위치/크기 계산
↓
페인트(리페인트) — 화면에 그리기
이 순서를 Critical Rendering Path(핵심 렌더링 경로) 라고 부릅니다.
리플로우와 리페인트의 차이
이 두 가지는 헷갈리기 쉬운데, 핵심은 간단합니다.
- 리플로우: 요소의 위치나 크기가 바뀔 때 발생합니다. 레이아웃을 다시 계산해야 하니까요.
- 리페인트: 색상이나 배경 같은 시각적 속성만 바뀔 때 발생합니다. 위치는 그대로니까 레이아웃 계산은 건너뜁니다.
중요한 건, 리플로우가 일어나면 리페인트도 반드시 따라온다는 점입니다. 위치가 바뀌면 당연히 다시 그려야 하니까요. 하지만 리페인트만 일어날 수도 있습니다.
그래서 width, height, margin, padding 같은 속성을 자주 바꾸면 성능에 영향을 줄 수 있습니다. 반면 color, background-color 같은 속성 변경은 상대적으로 가볍습니다.
퍼블리셔가 이걸 왜 알아야 할까?
지금 당장은 "그래서 뭐?" 싶을 수 있습니다. 하지만 이 기초가 나중에 큰 차이를 만듭니다.
React는 화면을 업데이트할 때 가상 DOM이라는 걸 씁니다. 진짜 DOM을 직접 건드리는 대신, 가상의 복사본에서 먼저 변경 사항을 계산하고 최소한의 변경만 실제 DOM에 반영합니다.
왜 이렇게 할까요? 바로 리플로우와 리페인트가 비싸기 때문입니다. DOM을 직접 자주 건드리면 브라우저가 레이아웃 계산과 페인트를 반복해야 하고, 화면이 느려집니다.
브라우저 렌더링 과정을 알면, 가상 DOM이 왜 등장했는지가 자연스럽게 이해됩니다. 다음 글에서는 자바스크립트 엔진이 코드를 어떻게 실행하는지 살펴보겠습니다.