← 개인 공부 · Frontend
STUDY NOTE · 개념 정리

브라우저 렌더링 과정 정리: Critical Rendering Path, Reflow와 Repaint

Frontend
브라우저는 HTML로 DOM, CSS로 CSSOM을 만들고, 둘을 합친 렌더 트리로 위치와 크기를 계산(Layout)한 뒤, 픽셀을 칠하고(Paint) 레이어를 합쳐(Composite) 화면에 그린다. 레이아웃부터 다시 하면 Reflow, 칠하기만 다시 하면 Repaint, 합성만 다시 하면 가장 싸다.

1. 전체 흐름

  1. HTML 파싱 → DOM: 바이트 → 문자 → 토큰 → 노드 → 트리
  2. CSS 파싱 → CSSOM: 선택자와 스타일 규칙을 트리로
  3. 렌더 트리(Render Tree): DOM + CSSOM에서 화면에 보이는 노드만 (display: none, <head> 제외)
  4. Layout (Reflow): 각 노드의 정확한 위치와 크기 계산
  5. Paint: 글자, 색, 테두리, 그림자 등을 레이어별로 픽셀로 칠할 목록 만들기
  6. Composite: 레이어를 순서대로 합쳐 화면에 표시 (GPU가 담당)

이 1~6까지, 첫 화면이 그려지기까지 꼭 거쳐야 하는 경로를 Critical Rendering Path(CRP)라고 한다.

2. 렌더링을 막는 것들

리소스파싱 차단렌더링 차단설명
CSS아니오예CSSOM이 없으면 렌더 트리를 못 만듦. 그래서 head에 두고 작게
일반 script예예만나는 순간 HTML 파싱을 멈추고 내려받아 실행 (JS가 DOM을 바꿀 수 있어서)
script async아니오 (실행 순간만 멈춤)-받는 대로 실행, 순서 보장 안 함 (광고, 분석 스크립트)
script defer아니오-파싱이 끝난 뒤 문서 순서대로 실행 (DOMContentLoaded 직전)
type="module"아니오-기본이 defer처럼 동작
img아니오아니오단, 크기를 안 정해 두면 로드 후 레이아웃이 밀림 (CLS)

또 하나: JS가 스타일 값을 읽으려면 CSSOM이 필요하므로, CSS가 다 오기 전까지는 그 뒤의 스크립트 실행도 기다린다.

3. Reflow vs Repaint vs Composite

구분다시 하는 단계일어나는 변경비용
Reflow (Layout)Layout → Paint → Compositewidth, height, margin, padding, top/left, font-size, 요소 추가·삭제, 창 크기 변경가장 큼 (자식·형제까지 다시 계산될 수 있음)
RepaintPaint → Compositecolor, background-color, visibility, box-shadow중간
Composite만Compositetransform, opacity (레이어로 분리된 경우)가장 작음 (GPU에서 처리)

애니메이션은 left, top 대신 transform: translate(), 사라지는 효과는 display나 visibility 대신 opacity를 쓰는 이유가 이것이다.

4. 강제 동기 레이아웃 (Layout Thrashing)

브라우저는 스타일 변경을 모아 뒀다가 다음 프레임에 한 번에 레이아웃을 계산한다. 그런데 중간에 offsetHeight, getBoundingClientRect(), scrollTop 같은 레이아웃 값을 읽으면, 정확한 값을 주려고 그 자리에서 바로 레이아웃을 계산한다.

// 나쁨: 읽기와 쓰기를 번갈아서 매 반복마다 레이아웃 강제
for (const el of items) {
el.style.width = box.offsetWidth + "px"; // 읽기(강제 레이아웃) → 쓰기
}

// 좋음: 읽기를 먼저 모으고, 쓰기를 한꺼번에
const w = box.offsetWidth;
for (const el of items) {
el.style.width = w + "px";
}
  1. 쓰기를 모으려면 requestAnimationFrame 안에서 처리하거나, 클래스 하나를 바꿔 스타일을 한 번에 적용한다.
  2. 많은 요소를 추가할 땐 DocumentFragment에 모아서 한 번에 붙인다.

5. 레이어와 합성

  1. transform, opacity 애니메이션, will-change, position: fixed, <video>, <canvas> 등은 별도 합성 레이어로 올라갈 수 있다.
  2. 레이어로 분리된 요소는 움직여도 다른 요소를 다시 칠하지 않는다. 그렇다고 레이어를 남발하면 GPU 메모리를 많이 먹는다. will-change는 실제로 움직이기 직전에만 쓴다.

6. 성능 지표와 연결

지표의미관련 단계
FCP첫 콘텐츠가 그려진 시점CRP 전체 (렌더링 차단 리소스 줄이기)
LCP가장 큰 콘텐츠가 그려진 시점큰 이미지·글꼴 로딩, 서버 응답
CLS레이아웃이 예기치 않게 밀린 정도크기 없는 이미지, 늦게 끼어드는 광고·글꼴
INP입력에 대한 다음 화면 반응 시간긴 JS 작업, 무거운 Reflow

7. 정리

  1. DOM + CSSOM → 렌더 트리 → Layout → Paint → Composite.
  2. CSS는 렌더링을, 일반 script는 파싱을 막는다. script는 defer가 기본 선택.
  3. 비용은 Reflow > Repaint > Composite. 움직임은 transform과 opacity로.
  4. 레이아웃 값을 읽고 쓰는 걸 섞지 않는다.
Gunmo Lee
브라우저 렌더링 과정 정리: Critical Rendering Path, Reflow와 Repaint | Gunmo's Dev Life