Render Tree
DOM + CSSOM 병합
DOM과 CSSOM을 합쳐, 눈에 보이는(visible) 요소와 그 스타일만 담은 렌더 트리를 만든다.
렌더 트리(Render Tree)는 DOM 트리와 CSSOM 트리를 결합해 만든, '실제로 화면에 그려질 내용'만을 담은 트리로, 각 노드에는 계산된 스타일(computed style)이 부착된다. 구성 과정은 DOM 루트부터 순회하며, 렌더링 출력에 반영되지 않는 노드(<script>, <meta>, <head> 등)와 display:none으로 숨겨진 노드를 제외하고, 남은 각 가시 노드에 매칭되는 CSSOM 규칙을 찾아 계산된 스타일과 함께 방출(emit)하는 방식이다. 여기서 핵심 구분은 display:none은 박스 자체가 생성되지 않아 렌더 트리에서 완전히 빠지지만, visibility:hidden은 보이지 않아도 공간을 차지하는 빈 박스로 렌더 트리에 남는다는 점이다. 텍스트를 감싸는 인라인/블록 컨텍스트를 맞추기 위해 브라우저가 자동으로 만드는 익명 박스(anonymous box)와, DOM에는 없지만 content로 생성되는 가상 요소(::before/::after) 및 ::marker 같은 노드도 렌더 트리에 포함된다. 이렇게 완성된 렌더 트리(브라우저별로 render tree/frame tree/box tree/fragment tree 등으로 불림)가 이후 레이아웃(위치·크기)과 페인트(픽셀)의 입력이 된다.
내부 구성
핵심 포인트
- 렌더 트리 = DOM(무엇을) + CSSOM(어떻게) 결합, 계산된 스타일이 각 노드에 부착
- 가시 노드만 포함: <head>, <meta>, <script>처럼 렌더링에 안 나오는 노드는 제외
- display:none → 박스 미생성, 렌더 트리에서 완전 제외 (레이아웃 참여 안 함)
- visibility:hidden → 렌더 트리에 포함, 공간은 차지하되 픽셀만 안 그림
- 익명 박스(anonymous box): 인라인/블록 혼재 시 브라우저가 자동 생성하는 이름 없는 박스
- 가상 요소 ::before/::after/::marker는 DOM에 없어도 content 규칙으로 렌더 트리에 추가됨
- DOM 노드와 렌더 트리 노드는 1:1이 아니다 (제외되거나, 하나가 여러 박스로 쪼개짐)
심화
흔한 오해는 '렌더 트리 노드 = DOM 노드'라는 생각이다. 실제로는 한 DOM 요소가 여러 개의 렌더 오브젝트(박스)로 쪼개질 수 있고(예: 여러 줄로 감싸지는 인라인 요소는 line box마다 박스가 생김), 반대로 display:none 요소는 DOM에는 있어도 렌더 트리에는 아예 없다. 그래서 display:none 토글은 레이아웃을 다시 만드는 비용이 크고(요소 재삽입 수준), visibility:hidden↔visible 토글은 이미 박스가 존재하므로 페인트만 다시 하면 되어 더 싸다. 이 차이는 성능 튜닝과 접근성(스크린 리더가 display:none은 읽지 않고 visibility:hidden도 대개 읽지 않지만 aria-hidden과는 별개)에서 실전 판단 근거가 된다. 용어에 대한 심화: 스펙 상 정확한 이름은 '박스 트리(box tree)'이고, Chromium(Blink)의 최신 RenderingNG에서는 레이아웃 결과가 불변(immutable)인 'fragment tree'로 표현된다. WebKit은 render tree, Gecko는 frame tree라 부른다. 면접에서 '렌더 트리'를 물으면 이 결합 규칙(가시 노드 + 계산 스타일)과 display:none/visibility:hidden 차이를 정확히 말하는 것이 핵심이고, 가상 요소·익명 박스까지 언급하면 깊이를 보여줄 수 있다.
쉽게 말하면 대본(DOM)과 의상표(CSSOM)를 합쳐, 실제로 무대에 오르는 배우 목록만 추리는 것.