6부 · 브라우저는 어떻게 화면을 그리나
← 5부 | 목차 | 다음: 7부 · 전체 흐름과 다음 단계 →
지금 다루는 단계: ⑥ 렌더링 — 받은 HTML·CSS·JS가 어떻게 눈에 보이는 픽셀이 되는가.
3부에서 서버가 HTML을 보내줬고, 4·5부에서 그 HTML·CSS·JS를 작성해 봤습니다. 그런데 1부에서 한 약속 — "그림은 서버가 아니라 브라우저가 그린다" — 가 실제로 어떻게 일어나는지는 아직 안 봤죠. 이번 부의 주제입니다.
브라우저는 설명서를 받아 조립하는 공장
브라우저가 받는 것은 완성된 이미지가 아니라 텍스트(HTML·CSS·JS)라는 설명서입니다. 브라우저는 이 설명서를 여러 공정을 거쳐 화면으로 조립합니다. 마치 가구 조립 설명서를 보고 실제 가구를 세우는 것과 같죠.
flowchart LR
HTML["HTML 텍스트"]:::doc --> DOM["DOM 만들기<br/>(요소 나무)"]:::render
CSS["CSS 텍스트"]:::doc --> CSSOM["스타일 규칙<br/>정리"]:::render
DOM --> RENDER["둘을 합쳐<br/>'무엇을 어디에 어떻게'<br/>계산"]:::render
CSSOM --> RENDER
RENDER --> LAYOUT["배치 계산<br/>(레이아웃)"]:::render
LAYOUT --> PAINT["픽셀로 칠하기<br/>(페인트)"]:::good
classDef doc fill:#e9d8fd,stroke:#6b46c1,color:#000
classDef render fill:#cfe8ff,stroke:#2b6cb0,color:#000
classDef good fill:#c6f6d5,stroke:#276749,color:#000
순서대로 풀어 보겠습니다.
1단계 · DOM: HTML을 '나무'로 바꾸기
브라우저는 HTML 텍스트를 위에서부터 읽으며, 4부에서 본 중첩 구조를 그대로 살린 나무(tree) 모양의 객체로 변환합니다. 이것이 DOM(Document Object Model, 문서 객체 모델)입니다.
예를 들어 이 HTML은:
<body> <h1>제목</h1> <p>문단 <strong>강조</strong></p> </body>
이런 나무가 됩니다:
flowchart TD
body["body"]:::doc
h1["h1<br/>'제목'"]:::doc
p["p"]:::doc
text["'문단 '"]:::doc
strong["strong<br/>'강조'"]:::doc
body --> h1
body --> p
p --> text
p --> strong
classDef doc fill:#e9d8fd,stroke:#6b46c1,color:#000
왜 굳이 나무로 만들까요? 두 가지 이유가 있습니다.
- 부모-자식 관계가 그대로 표현되어, 배치와 스타일 상속을 계산하기 좋습니다.
- JavaScript가 이 나무를 만질 수 있습니다. 5부에서
document.getElementById(...)로 요소를 찾아 글자를 바꿨죠? 그document가 바로 이 DOM 나무의 뿌리입니다. JS는 이 나무의 가지를 더하고, 빼고, 바꾸며 페이지를 살아 움직이게 합니다.
즉 DOM은 'HTML의 살아있는 버전'입니다. HTML은 처음 배달된 설명서, DOM은 브라우저 안에서 그걸 조립해 만든 — 그리고 JS로 계속 고칠 수 있는 — 실물 구조입니다.
2단계 · 스타일 합치기
브라우저는 CSS도 읽어 "어떤 요소에 어떤 모양을 줄지" 규칙표로 정리합니다(이걸 CSSOM이라 부르지만 용어는 안 외워도 됩니다). 그런 다음 DOM 나무의 각 요소에 해당 스타일을 짝지어, "이 <h1>은 남색·가운데 정렬"처럼 '무엇을 어떻게 그릴지'가 정해진 최종 목록을 만듭니다.
3단계 · 레이아웃: 어디에 놓을지 계산
이제 각 요소가 화면의 어느 위치에, 얼마만 한 크기로 놓일지를 계산합니다. 이를 레이아웃(layout) 또는 '리플로(reflow)'라고 합니다.
화면 너비가 얼마인지, 어떤 요소가 어떤 요소 아래·옆에 오는지, 여백은 얼마인지를 따져 모든 요소의 좌표와 크기를 정합니다. 창 크기를 줄이면 글이 다시 줄바꿈되며 재배치되죠? 그게 레이아웃이 다시 계산되는 모습입니다.
4단계 · 페인트: 실제로 칠하기
위치와 크기가 정해지면, 마지막으로 브라우저가 화면에 실제 픽셀을 칠합니다(paint). 글자, 색, 테두리, 이미지가 이때 비로소 눈에 보이는 그림이 됩니다.
여기까지가 1부에서 약속한 ⑥ 렌더링의 전모입니다. 정리하면: HTML → DOM 나무 → 스타일 결합 → 위치 계산 → 픽셀 칠하기.
페이지 하나에 요청이 여럿인 이유
3부의 실습에서 "페이지 하나 여는 데 요청이 줄줄이 나간다"고 했죠. 이제 이유가 보입니다. 브라우저가 HTML을 읽다가 중간에 이런 줄을 만나면:
<img src="profile.jpg" alt="..."> <link rel="stylesheet" href="style.css"> <script src="app.js"></script>
각 파일(이미지·CSS·JS)을 받으려고 추가 HTTP 요청을 또 보냅니다. 즉 HTML은 "이런 부품들이 더 필요하다"는 주문 목록이기도 한 셈입니다. 부품이 다 도착해야 페이지가 완성됩니다. 이것이 앞 부들의 개요도에서 "추가 파일 요청" 점선이 의미하던 것입니다.
sequenceDiagram
participant B as 브라우저
participant S as 서버
B->>S: GET /index.html
S-->>B: HTML 본문
Note over B: HTML 읽다가 img·css·js 발견
B->>S: GET /style.css
B->>S: GET /profile.jpg
B->>S: GET /app.js
S-->>B: 각각의 파일 응답
Note over B: 모두 모아 DOM·스타일 완성 → 렌더링
왜 어떤 페이지는 늦게 뜨나: 렌더 차단
여기까지 오면 "왜 어떤 사이트는 글이 늦게 뜨고 깜빡일까?"를 이해할 단서가 생깁니다. 브라우저는 HTML을 위에서부터 읽다가 CSS·JS를 만나면, 경우에 따라 그 파일을 다 받을 때까지 그리기를 잠시 멈춥니다. 이를 '렌더 차단(render-blocking)'이라고 합니다.
- CSS: 보통 먼저 다 받아야 합니다. 스타일을 모르고 그렸다가 다시 그리면 화면이 번쩍이니까요.
- JavaScript:
<script>를 만나면 기본적으로 거기서 멈추고 JS를 먼저 처리합니다. 그래서 무거운 JS가 위에 있으면 페이지가 늦게 뜹니다.
그래서 실무에서는 <script>를 <body> 끝에 두거나(우리 실습이 그랬죠), defer(문서 다 읽은 뒤 실행)·async(따로 받아 준비되면 실행) 같은 표시를 붙여 차단을 줄입니다. 지금은 "JS 위치가 속도에 영향을 준다"는 감만 잡아도 충분합니다.
<!-- 문서를 다 읽은 뒤 실행 → 화면을 막지 않음 --> <script src="app.js" defer></script>
한 번 그리면 끝이 아니다: 리플로와 리페인트
렌더링은 첫 화면에서 끝나지 않습니다. 5부에서 JS로 글자를 바꾸거나 요소를 추가했죠? 그렇게 DOM이나 스타일이 바뀌면 브라우저는 영향받은 부분을 다시 계산하고 다시 칠합니다.
- 리플로(reflow): 위치·크기가 바뀌어 레이아웃을 다시 계산하는 것 (비용이 큼).
- 리페인트(repaint): 위치는 그대로고 색 같은 겉모습만 다시 칠하는 것 (상대적으로 가벼움).
창 크기를 바꾸거나, 목록에 항목을 추가하거나, 애니메이션이 돌 때 이 과정이 반복됩니다. 지금 단계에서는 "화면이 바뀔 때마다 브라우저가 다시 일한다"는 사실만 기억하면 됩니다.
클라이언트와 서버, 일은 어디서 도나
여기서 초보가 자주 헷갈리는 점을 정리하겠습니다. 웹의 일 처리는 두 장소에서 나뉘어 일어납니다.
| 구분 | 어디서 도나 | 무엇을 하나 | 예 |
|---|---|---|---|
| 클라이언트 측<br/>(프런트엔드) | 내 브라우저 | DOM 조립, 렌더링, JS 동작 | 버튼 클릭 반응, 화면 꾸미기 |
| 서버 측<br/>(백엔드) | 멀리 있는 서버 | 데이터 저장·조회, 페이지 생성 | 로그인 확인, 글 목록 불러오기 |
우리 실습 페이지는 전부 클라이언트 측에서 돕니다(파일을 더블클릭해 브라우저가 다 처리했죠). 반면 로그인·결제·검색처럼 데이터와 보안이 걸린 일은 서버 측에서 처리해야 합니다 — 그래야 비밀번호나 데이터를 안전하게 다룰 수 있으니까요. 이 둘을 합쳐 만드는 게 진짜 웹 서비스입니다.
이 부에서 기억할 것
- 브라우저는 텍스트 설명서(HTML·CSS·JS)를 받아 DOM 나무 → 스타일 결합 → 레이아웃 → 페인트 순으로 화면을 조립한다.
- DOM은 HTML의 '살아있는 나무 버전'이고, JavaScript는 이 나무를 만져 페이지를 바꾼다.
- HTML 안의 이미지·CSS·JS는 각각 추가 요청으로 받아 온다(그래서 요청이 여럿).
- CSS·JS는 렌더 차단을 일으킬 수 있어, JS는 보통 문서 끝이나
defer로 둔다. - 화면이 바뀌면 브라우저는 리플로(재배치)·리페인트(재칠)로 다시 그린다.
- 일은 클라이언트 측(브라우저)과 서버 측(백엔드)으로 나뉜다. 보안·데이터가 걸리면 서버의 몫.
마지막 부에서는 1부부터 6부까지를 하나의 흐름으로 다시 꿰고, 우리 실습 페이지를 세상에 공개하는 법과 더 배울 방향을 안내합니다.