frontend/javascript

🟨 2-23. 브라우저 렌더링 과정 — 자바스크립트, CSS, DOM이 함께 그려지는 진짜 순서

mirabo01 2025. 11. 7. 08:55

1. 브라우저 렌더링이란?

렌더링(Rendering)은
브라우저가 HTML, CSS, JavaScript, 이미지 등의 자원을 해석해
사용자에게 보이는 화면(Pixels) 을 만드는 과정이다.

즉, “텍스트 파일을 시각적 결과로 변환하는 과정”이 바로 렌더링이다.


2. 렌더링의 전체 흐름

브라우저가 HTML 파일을 받으면 다음 순서로 진행된다 👇

1️⃣ HTML 파싱 → DOM 트리 생성  
2️⃣ CSS 파싱 → CSSOM 트리 생성  
3️⃣ DOM + CSSOM → Render Tree 결합  
4️⃣ Layout (배치) → 요소 크기와 위치 계산  
5️⃣ Paint (그리기) → 픽셀 단위로 색상, 테두리, 그림자 적용  
6️⃣ Composite (합성) → GPU가 화면에 출력

이 전체 과정을 Critical Rendering Path (CRP) 라고 한다.


3. 단계별로 살펴보기

1️⃣ HTML 파싱 → DOM 생성

HTML은 위에서 아래로 순서대로 읽히며,
태그마다 노드(node) 로 변환되어 DOM(Document Object Model) 트리를 만든다.

<html>
  <body>
    <h1>제목</h1>
    <p>내용</p>
  </body>
</html>

→ 변환 결과 (DOM Tree)

Document
 └── html
     └── body
         ├── h1
         └── p

✅ JS에서 접근하는 document.querySelector() 의 대상이 바로 이 DOM이다.


2️⃣ CSS 파싱 → CSSOM 생성

브라우저는 CSS 파일을 동시에 읽어 CSSOM (CSS Object Model) 을 만든다.

body {
  color: black;
}
h1 {
  font-size: 24px;
}

→ CSSOM Tree

CSS Rules
 ├── body { color: black }
 └── h1 { font-size: 24px }

✅ CSS는 렌더링 차단(Render Blocking) 리소스다.
✅ 즉, CSS를 모두 파싱하기 전까지 브라우저는 화면을 그리지 않는다.


3️⃣ Render Tree 생성

브라우저는 DOM과 CSSOM을 결합해 렌더 트리(Render Tree) 를 만든다.
렌더 트리는 화면에 실제로 표시될 요소만 포함한다.

예를 들어, display: none 요소는 포함되지 않는다.

Render Tree
 ├── h1 (font-size: 24px, color: black)
 └── p (color: black)

4️⃣ Layout (배치)

렌더 트리의 각 노드가
화면 어디에, 어떤 크기로 위치해야 하는지를 계산한다.

이를 Reflow (리플로우) 또는 Layout 단계라고 부른다.

<div style="width: 100px; height: 50px; margin: 10px;"></div>

→ 이 정보를 기반으로 브라우저가 픽셀 좌표를 계산한다.

✅ 리플로우는 DOM의 구조나 크기가 변할 때마다 다시 일어난다.


5️⃣ Paint (그리기)

Layout이 끝나면, 브라우저는
요소의 색상, 배경, 테두리, 그림자 등 시각적 속성을 칠한다.

이 과정을 Repaint (리페인트) 라고 한다.

✅ CSS 색상, 배경 변경 → Repaint만 일어남
✅ 크기나 위치 변경 → Reflow + Repaint 모두 발생


6️⃣ Composite (합성)

이제 Paint된 레이어들을 GPU가 합성(Composite)하여
화면에 실제 픽셀로 렌더링한다.

💡 예를 들어,
브라우저는 position: fixed나 transform, opacity 속성이 있는 요소를
“독립적인 레이어(Layer)”로 분리해 GPU에서 효율적으로 합성한다.


4. 자바스크립트가 렌더링을 막는 이유

자바스크립트는 HTML 파싱 도중 만나면
브라우저가 파싱을 일시 중단하고 JS를 먼저 실행한다.

<script src="app.js"></script>

✅ JS는 DOM을 조작할 수 있기 때문에
파싱 도중 실행되지 않으면 결과가 달라질 수 있다.

➡ 따라서 JS는 렌더링 차단(Render Blocking) 요인이 된다.


5. async / defer 속성으로 최적화

이 문제를 해결하기 위해
스크립트 로딩을 제어하는 속성 2가지를 사용할 수 있다.

속성 실행 시점 특징

async 다운로드 완료 즉시 실행 병렬로 로드, 순서 보장 X
defer DOM 파싱 완료 후 실행 순서 보장 O, 렌더링 차단 X
<script src="app.js" defer></script>

✅ defer는 HTML 파싱을 멈추지 않으므로
렌더링 속도를 높이는 가장 안전한 방법이다.


6. Reflow & Repaint 최적화

렌더링 성능 문제의 대부분은
Reflow (Layout)Repaint (Painting) 에서 발생한다.

구분 발생 원인 비용

Reflow DOM 구조 변경, 크기/위치 조정 높음
Repaint 색상/배경 변경 낮음

✅ Reflow 최소화 팁

  1. DOM 변경 시, 한 번에 묶어서 처리하기❌ 이렇게 하면 매번 Reflow 발생
    ✅ 해결 → el.style.cssText = "width:200px;height:100px;margin:10px";
  2. const el = document.getElementById("box"); el.style.width = "200px"; el.style.height = "100px"; el.style.margin = "10px";
  3. display: none으로 숨긴 뒤 조작 후 다시 표시하기
  4. DOM 조작 대신 classList.toggle()로 스타일 변경

7. Layout Thrashing 방지

JS에서 DOM의 offsetWidth, getBoundingClientRect() 같은 속성을 자주 읽으면
Layout Thrashing(레이아웃 쓰래싱) 현상이 발생한다.

for (let i = 0; i < 1000; i++) {
  box.style.width = box.offsetWidth + 1 + "px";
}

✅ 읽기(리플로우)와 쓰기(스타일 변경)가 반복되면서 성능 급락
➡ 해결: 읽기 → 쓰기 순서로 묶기


8. 브라우저의 프레임 렌더링 주기

브라우저는 초당 60fps(약 16.6ms 주기)로 렌더링 루프를 돌린다.

Frame(16ms)
 ├─ Input → Script → Style → Layout → Paint → Composite

💡 JS가 16ms 안에 실행되지 않으면
프레임 드롭(Frame Drop)이 발생 → “버벅임” 느낌

➡ 따라서 긴 연산은 Web Worker나 requestIdleCallback 으로 분리하는 게 좋다.


9. 실제 렌더링 최적화 예시

requestAnimationFrame(() => {
  element.style.transform = "translateX(100px)";
});

✅ transform은 GPU 가속을 활용하므로
Layout(Reflow) 없이 Paint/Composite만 발생
➡ CSS Transition, Animation은 대부분 이 구조를 이용한다.


10. 렌더링 파이프라인 요약

단계 주요 결과물 비고

HTML 파싱 DOM Tree 텍스트 → 객체
CSS 파싱 CSSOM Tree 스타일 구조
Render Tree DOM + CSSOM 결합 실제 렌더링 대상
Layout 위치/크기 계산 Reflow 발생
Paint 시각적 속성 칠하기 Repaint 발생
Composite GPU 합성 최종 픽셀 출력

11. 정리

개념 핵심 내용

DOM HTML 구조 트리
CSSOM 스타일 구조 트리
Render Tree 실제 렌더링 대상 결합 구조
Reflow 레이아웃 계산 단계
Repaint 시각적 속성만 다시 그림
Composite GPU 합성 후 화면 표시
Render Blocking JS/CSS가 렌더링 중단시키는 현상
최적화 Reflow 최소화 + GPU 활용

12. 마무리

이제 브라우저가 “코드를 눈에 보이게 만드는 과정”이 명확히 보일 거야.
이 구조를 이해하면 “성능을 높인다”는 게 단순한 추상적 개념이 아니라
실제 렌더링 파이프라인을 제어하는 행위라는 걸 깨닫게 된다.

“렌더링 최적화란, 브라우저의 일꾼(엔진)들에게 불필요한 일을 덜 시키는 것이다.”