안녕! 나는 러버덕이야!
이번 시간에는 브라우저가 랜더링 되는 과정을 한번 살펴볼거야 덕!
오늘도 신나게 달려볼까??
Q. 안녕!! 나는 러버덕이야. 오늘은 브라우저 랜더링에 대해서 알아보려고 해!
A. 좋아!! 브라우저 랜더링은 웹개발자에게 있어서 모르면 안되는 필수 지식이지!
Q. 브라우저라고 하면 우리가 인터넷을 할 수 있는 창을 얘기하는 거야?
A. 맞아! 브라우저는 정확히는 웹 브라우저를 말하는 건데…
브라우저(웹 브라우저, Web Browser)는 웹사이트를 탐색하고 표시하는 프로그램이야.
우리가 컴퓨터를 하면 많은 프로그램을 볼 수 있지?
나는 게임을 좋아하지는 않지만, 롤이나 배그 같은 것도 하나의 프로그램이지!
이 웹 브라우저는 사용자가 인터넷에 접속해서 웹페이지를 볼 수 있도록 해주는 소프트웨어라고 보면 돼.
대표적인 웹 브라우저로는
- Google Chrome (크롬)
- Mozilla Firefox (파이어폭스)
- Microsoft Edge (엣지)
- Apple Safari (사파리)
- Opera (오페라)
등이 있을 것 같아.
브라우저의 주요 기능을 살펴보면
- 웹페이지 렌더링: HTML, CSS, JavaScript를 해석해서 화면에 표시
- 인터넷 탐색: URL 입력 또는 검색 엔진을 통해 웹사이트 방문
- 북마크(즐겨찾기): 자주 방문하는 사이트를 저장
- 쿠키 및 캐시 관리: 웹사이트 정보를 저장해서 로딩 속도 향상
- 개발자 도구 제공: 웹 개발을 위한 디버깅 및 분석 기능 (F12 또는 Ctrl + Shift + I)
이런 것들이 있는데, 특히 1번, 4번, 5번이 웹 개발자와 관련이 있는 기능이라고 생각하면 될 것 같아.
특히 오늘은 1번에 대해서 얘기를 나눠보려고 하는거야.
Q. 나는 크롬을 주로 쓰는데, 이 외에도 많은 브라우저들이 있구나!
A. 맞아. 그리고 브라우저마다 호환성이 다 달라서 잘 살펴보고 코드를 작성해야 해.
이게 무슨 말이냐면, 내가 쓰려고 하는 메서드나 라이브러리가 어느 브라우저에서는 되고, 어느 브라우저에서는 안 될 수가 있어.
예를 들어서 Array.prototype.map
라는 ****메서드가 JavaScript에 있는데, 이 메서드가 내가 쓰는 브라우저에서 호환이 잘 되는지 보려면 페이지 제일 하단에 브라우저 호환성에 대해서 설명이 나와 있어.
이런식으로 말야!!
브라우저마다 엔진도 다르고, 최적화 과정도 다르기 때문에 어떤 브라우저에서 동작할지를 처음에 개발하기 전에 생각해보는 것도 좋을 것 같아!
Q. 하나의 아이스크림도 여러 브랜드가 있는 것처럼 브라우저도 마찬가지구나!
A. 나는 참고로 탱크보이를 좋아해! 술 먹고 해장용으로 딱…
Q. 바로 다음 질문! 그럼 랜더링이 뭐야?
A. 랜더링은 말야…
우리가 작성한 HTML, CSS, JavaScript를 브라우저에서 해석하고, 화면에 보여지는걸 말해.
이 한문장에는 아주 많은 과정들이 함축되어 있어.
먼저 전체적인 과정을 그림으로 보여줄게!
특히 DOM 트리 생성 → CSSOM 트리 생성 → 랜더 트리 생성 → 레이아웃 → 페인트 단계를 중요 렌더링 경로 (Critical Rendering Path)라고도 표현을 해.
왜 저 과정을 CRP라고 표현을 할까?
중요 렌더링 경로 (CRP)는 브라우저가 HTML, CSS, Javascript를 화면에 픽셀로 변화하는 일련의 단계를 말하며, 이를 최적화하는 것은 렌더링 성능을 향상시키기 때문이지!!
아무래도 성능 최적화를 하는 것이, 개발자의 역량을 볼 수 있는 중요한 부분이기도 해.
그럼 우리도 잘하는 개발자가 되려면 성능 최적화를 잘해야겠지??
앞으로 나와 계속 알아간다면 자연스럽게 성능 최적화 부분에 대해서도 얘기를 할테니 천천히 잘 따라와주기만 해줘 😎
그럼 이제부터 단계별로 어떻게 진행되는지 알아볼까?
✅ 1. HTML 파싱 및 DOM 트리 생성
가장 먼저 브라우저는 HTML 파일을 읽고(파싱), DOM(Document Object Model) 트리를 생성해.
🍯 파싱
파싱이란, 특정 형식의 데이터를 분석하고 의미를 이해하는 과정을 말해!
컴퓨터는 결국에는 0과1밖에 모르는 바보인데, 우리가 알아볼 수 있는 언어로 변환을 해야 이해하고 써먹을 수 있잖아?
그러한 과정이 바로 파싱이라는 거야.
DOM은 HTML 문서의 계층적 구조를 표현하는 객체 모델로, 브라우저가 HTML로 작성된 여러 요소들을 Javascript가 이해하고 조작할 수 있도록 변환시킨 객체야.
그래서 우리가 뭔가 코드를 수정하면, 직접 화면을 건드리는게 아니고 DOM트리를 수정해서 그게 화면에 반영이 되는거야.
DOM은 문서의 요소를 트리구조로 표현하며, 각 노드(Node)는 HTML 태그를 나타냅니다. 그리고 이 트리구조를 ‘DOM 트리’라고 불러.
한번 예를 살펴볼까?
📌 예시: DOM 트리 변환
<!DOCTYPE html>
<html>
<body>
<div class="parent">
<div class="child1">첫째 아들</div>
<div class="child2">둘째 딸</div>
</div>
</body>
</html>
위의 코드를 바탕으로 DOM 트리를 그린다고 하면
이런식으로 만들어질거야.
DOM 트리는 HTML 문서를 계층적으로 표현한 트리구조로, HTML 문서의 각 요소(태그), 속성, 텍스트는 DOM 트리에서 하나의 노드로 표현이 돼.
🍯 노드
노드란 넓은 의미에서는 트리에서 데이터를 저장하는 기본 구성 단위를 의미해.
JavaScript에서는 특히 노드라는 데이터 타입(추상 클래스)이 있어서, DOM 트리가 이 노드라는 데이터 타입의 요소들로 이루어져있다고 볼 수 있어.
그럼 DOM 트리에서 우리가 다루는 최상위 노드는 document인데, document가 Node 타입이라는 걸 어떻게 알 수 있을까?
어떤 객체를 상속 받으면 그 객체의 프로토타입도 같이 상속 받게 되는데, 이걸 확인해 보면 돼!!
Object.getPrototypeOf(document)
// 그 객체의 프로토타입을 보여준다.
constructor: ƒ HTMLDocument()
...
[[Prototype]]: Document
...
[[Prototype]]: Node
...
[[Prototype]] : EventTarget

이런 관계인 걸 확인해 볼 수 있어. 아직 이해가 되지 않아도 괜찮아. 다음 시간에 자세히 설명해 줄게!!
이 트리구조 덕분에, 부모-자식, 형제 노드 간의 관계를 파악할 수 있으며, 쉽게 요소를 탐색하거나 수정할 수 있는거지.
✅ 2. CSS 파싱 및 CSSOM 트리 생성
HTML을 파싱해 DOM 트리를 생성했다면, 이제 브라우저는 CSS 파일을 읽어(파싱) CSSOM(CSS Object Model) 트리를 생성해.
CSSOM은 브라우저가 CSS를 파싱하여 트리 구조로 표현한 객체 모델로, HTML 문서의 각 요소에 적용된 CSS 스타일 규칙을 나타내며, DOM과 결합해(랜더트리) 화면에 표현될 준비를 하지.
📌 예시: CSSOM 트리로 변환
.body{
margin: 30px;
}
.child1 {
font-size: 20px;
}
.child2{
color : blue;
}
위의 코드를 바탕으로 CSSOM 트리를 그린다고 하면
이런식으로 표현이 될거야.
✅ 3. 랜더 트리 생성
CSS를 파싱해 CSSOM까지 생성했다면, 브라우저는 이제 DOM과 CSSOM을 결합해 랜더 트리(Render Tree)를 생성해.
렌더 트리는 화면에 보여질 요소들만 포함하고 있으며, 각 요소에 적용될 스타일과 위치에 대한 정보를 담고 있어.
🍯 화면에 보여질 요소들만 포함?
화면에 보여질 요소들만 포함된다는게 무슨말일까?
여기 html 코드를 한번 보자.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script defer type="module" src="src/main.js"></script>
</head>
<body>
<div class="parent">
<div class="child1">첫째 아들</div>
<div class="child2">둘째 딸</div>
</div>
</body>
</html>
body태그 말고 head태그가 있지? head태그는 보통 메타데이터와 관련된 정보들이 포함돼.
그런데 이 head태그의 정보들은 실제로 우리가 보는 브라우저에 보여지는 요소들이 아니라서 랜더 트리가 만들어질 때 제외가 되는거지.
그리고 style이 display: none이 있는 노드(예: 사용자 에이전트 스타일시트에서 찾을 수 있는 { display: none; })는 렌더링된 출력에 나타나지 않으므로 렌더링 트리에 포함되지 않아.
visibility: hidden 적용된 노드는 공간을 차지하므로 렌더링 트리에 포함돼.
DOM 트리와 CSSOM을 결합한 렌더 트리를 그림으로 나타내면 다음과 같아.
✅ 4. 레이아웃(reflow)
렌더 트리가 생성되면 브라우저는 각 요소의 위치와 크기를 계산하는 레이아웃(Layout) 단계에 들어가.
이 과정에서는 요소가 화면에서 어디에 위치할지, 그리고 어떤 크기를 가질지 등을 결정이 돼.
이 글에서 사용하고 있는 코드에서는 body에 margin: 30px
이 적용되면, class 이름이 child1와 child2인 요소는 30px의 여백을 두고 배치가 되겠지?
✅ 5. 페인트
레이아웃 단계 이후, 브라우저는 요소의 스타일과 내용을 바탕으로 화면에 픽셀을 그리는 단계야.
이 단계를 페인트(Paint) 단계라고 부르며, 레이아웃 단계에서 계산된 요소들의 위치와 크기를 참고해, 각 요소에 적용된 스타일 속성(색상, 텍스트, 그림자, 테두리 등)을 시각적으로 표현하는 거지.
즉, 브라우저는 각 요소의 시각적인 속성을 기반으로 픽셀 데이터를 생성하며, 데이터들은 화면에 표시될 준비를 하는 단계지.
그럼 위의 예시를 생각해 보면
class 이름이 child1인 요소는 글자 크기 20px, 텍스트 내용은 ‘첫째 아들’으로 화면에 그려지고,
class 이름이 child2인 요소는 글자색이 파란색으로 그려질거야.
페인트 과정에서 브라우저는 각 요소의 시각적인 속성을 기반으로 페인트 레이어(Paint Layer)를 생성하는데, 요소들의 특정 속성(z-index, position, opacity, 등)에 따라 독립적인 레이어가 생성될 수 있어.
✅ 6. 합성(Compositing)
페인트 과정에서 생성된 여러 개의 레이어들은 합성(Compositing) 단계에서 하나의 화면으로 결합이 돼.
브라우저는 각 레이어를 올바른 순서로 합성해 화면에 정확히 렌더링이 되는거지.
특히 요소가 겹치는 경우, z-index나 position과 같은 속성을 고려해 겹침 순서를 정확히 처리를 해야해.
여러 레이어들이 하나로 합쳐지는 과정은 아래의 그림을 보면 쉽게 이해할 수 있을거야.
자 이제 지금까지 브라우저 랜더링 과정에 대해서 설명을 해줬어.
이제 웹페이지가 보이기까지 얼마나 많은 과정이 거치는지 알겠지?
Q. 역시 눈에 보이는게 다가 아니구나… 안 보이는 뒤에서 열일을 하고 있었군 덕!
A. 원래 단순해 보이는게, 그 단순함을 위해서 많은 고민과 과정이 녹아들어져 있는거지.
Q. 좋아! 마지막으로 정리해 줄 수 있어?
A. 알았어 내가 그럼 마지막으로 정리를 해서 알려줄게!
🎯 결론
브라우저 렌더링 과정은
1. HTML 파싱 & DOM 트리 생성
- HTML을 위에서 아래로 읽으면서 DOM(Document Object Model) 트리 생성
- 태그를 토큰화 → 노드 변환 → 트리 구조로 조립
2. CSS 파싱 & CSSOM 트리 생성
- <link rel="stylesheet">, <style> 등을 만나면 CSS 다운로드 및 파싱
- CSSOM(CSS Object Model) 트리 생성 (스타일 규칙을 적용할 구조)
3. 렌더 트리(Render Tree) 생성
- DOM과 CSSOM을 결합하여 렌더 트리 생성
- 화면에 표시할 요소만 포함 (예: display: none은 제외)
4. 레이아웃 (Layout, Reflow)
- 렌더 트리를 기반으로 각 요소의 크기와 위치 계산
- 화면 크기, 글자 크기, 마진/패딩 등 고려
5. 페인팅 (Painting)
- 계산된 요소들을 픽셀 단위로 변환하여 화면에 그림
- 색상, 그림자, 테두리 등 시각적 스타일 적용
6. 합성 (Compositing)
- 여러 레이어를 GPU 가속을 활용해 최적화하여 합성
- 빠른 화면 업데이트를 위해 일부만 다시 그림 (Repaint, Reflow 최소화)
✅ 참조
- https://yozm.wishket.com/magazine/detail/2909/
- https://web.dev/learn/performance/understanding-the-critical-path?hl=ko
- https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/How_browsers_work
- https://developer.mozilla.org/ko/docs/Web/Performance/Guides/Critical_rendering_path
'러버덕의 개발 이야기' 카테고리의 다른 글
러버덕의 개발 이야기 - target, eventTarget (0) | 2025.03.24 |
---|---|
러버덕의 개발 이야기 - var, let, const (2) | 2025.03.17 |