화면이 그려지는 것은 마법이 아니다
프론트엔드 개발(Vue.js)을 처음 시작했을 때, 나는 브라우저를 그저 ‘코드를 보여주는 액자’ 정도로만 생각했다. <div>를 쓰면 네모가 나오고, color: red를 쓰면 빨간색이 되는 게 당연했다.
하지만 실무에서 애니메이션이 버벅거리거나, 스크롤을 내릴 때 화면이 뚝뚝 끊기는 현상(Jank)을 겪으면서 내 생각은 바뀌었다. “왜 똑같은 코드를 짰는데 크롬에서는 부드럽고, 인터넷 익스플로러(IE)에서는 끊길까?” “왜 자바스크립트로 스타일을 조금만 바꿨는데 CPU가 치솟을까?”
알고 보니 브라우저는 단순한 액자가 아니었다. 브라우저는 우리가 보낸 텍스트(HTML/CSS)를 해석해서, 픽셀 하나하나를 수학적으로 계산해 찍어내는 거대한 ‘화가(Painter)’이자 ‘건축가’였다.
지난 시간, 우리는 거친 네트워크 도로를 뚫고 데이터를 무사히 배송했다. 이번 시간에는 도착한 데이터 박스(패킷)를 뜯어서, 브라우저가 어떻게 화면이라는 그림을 그려내는지 알아보자. 이것이 Re: Booting CS 기초 시리즈의 마지막 이야기다.

도착한 화물, 조립을 시작하다
우리의 ‘디지털 물류 센터’ 세계관에서, 이제 물건(HTML 파일)이 고객의 집(브라우저)에 도착했다. 하지만 도착한 것은 완제품이 아니라 ‘조립 설명서’다. 브라우저 엔진(렌더링 엔진)이라는 작업팀은 이 설명서를 보고 즉시 조립에 들어간다. 이 과정을 렌더링 파이프라인(Rendering Pipeline)이라고 한다.
1단계: 설계도 분석 (Parsing & DOM Tree)
가장 먼저 도착한 HTML 텍스트를 읽고, ‘뼈대’를 만든다.
<html>은 뿌리(Root),<body>는 몸통,<div>는 가지…- 이렇게 트리(Tree) 구조로 만든 것을 DOM(Document Object Model)이라고 한다. 자바스크립트가 나중에 이 뼈대를 건드릴 수 있게 만드는 API이기도 하다.
2단계: 인테리어 디자인 (CSSOM Tree)
그다음 CSS 파일을 읽어서 ‘스타일 규칙’을 만든다.
- “모든
div는 빨간색”, “클래스가box인 녀석은 크기 100px” - 이것을 CSSOM(CSS Object Model)이라고 한다.
3단계: 작업 지시서 작성 (Render Tree)
이제 뼈대(DOM)와 디자인(CSSOM)을 합친다. 여기서 중요한 점은 ‘실제로 화면에 보일 것들’만 추려낸다는 것이다.
display: none속성이 있는 요소는? 화면에 안 보일 녀석이니 렌더 트리에서 제외된다. (공간도 차지하지 않음)- 반면
visibility: hidden은? 안 보이지만 공간은 차지하므로 렌더 트리에 포함된다.

[Code Verification] 리플로우(Reflow)와 리페인트(Repaint)
이제 진짜 중요한 단계다. 성능 최적화의 핵심이 여기에 있다. 렌더 트리가 만들어지면 브라우저는 두 가지 무거운 작업을 수행한다.
- 레이아웃(Layout) / 리플로우(Reflow): 각 요소가 ‘어디에, 어떤 크기로’ 배치될지 수학적으로 계산한다. (건축 설계)
- 페인트(Paint) / 리페인트(Repaint): 계산된 위치에 실제로 ‘색을 칠한다’. (도색 작업)
코드로 이 비용의 차이를 느껴보자.
const box = document.getElementById('box');
// Case 1: 레이아웃(Reflow)을 유발하는 코드 (비싸다!)
// 크기나 위치를 바꾸면, 주변 요소들의 위치까지 다시 다 계산해야 한다.
box.style.width = '200px';
box.style.height = '200px';
box.style.margin = '20px';
// Case 2: 페인트(Repaint)만 유발하는 코드 (비교적 싸다)
// 위치는 그대로두고, 색깔만 바꾼다. 계산 과정 없이 칠하기만 다시 하면 된다.
box.style.backgroundColor = 'blue';
box.style.color = 'white';
box.style.visibility = 'hidden';
분석:
width변경: 건물의 크기를 바꾸는 공사다. 옆 건물도 밀려나고, 그 옆 건물도 밀려난다. 브라우저는 전체 계산기를 다시 두드려야 한다. (Reflow 발생 -> 성능 저하의 주범)color변경: 건물 크기는 그대로 두고 페인트칠만 다시 한다. 계산할 필요가 없다. (Repaint 발생 -> 빠름)
실무에서 “애니메이션이 버벅거린다”는 대부분 width, left, top 같은 레이아웃 속성을 실시간으로 건드렸기 때문에 발생한다. 이럴 땐 transform 같은 속성을 써서 레이아웃 계산을 건너뛰는 테크닉이 필요하다.
실무 조언: 브라우저를 괴롭히지 마라
학부 때는 이런 걸 몰랐으니 자바스크립트로 DOM을 마구잡이로 조작했다. for 문을 돌면서 요소 하나하나의 크기를 바꾸고, 스타일을 입혔다. 브라우저 입장에서는 1초에 수십 번씩 건물을 부수고 다시 짓는 고문을 당한 셈이다.
성능을 지키는 팁:
- DOM 조작은 모아서 한 번에: 스타일을 하나씩 바꾸지 말고,
class를 미리 만들어두고className만 딱 한 번 바꿔라. - 애니메이션은 GPU에게:
left,top대신transform: translate()를 쓰면 레이아웃 단계를 건너뛰고 GPU가 처리해 준다. - 숨길 때의 차이: 아예 없애버릴 거면
display: none(렌더 트리 제외), 자리만 비워둘 거면visibility: hidden(렌더 트리 포함)을 구분해서 써라.

시리즈 1을 마치며: 다시 부팅된 나의 CS
이 글을 끝으로 [Re: Booting] CS 기초 시리즈가 막을 내렸다.
우리는 긴 여정을 함께했다.
- 언어(Language): 사람이 쓴 코드가 기계어로 번역되고(빌드),
- 메모리(Memory): 스택과 힙이라는 방에 입주하며,
- 프로세스(OS): 스레드라는 분신술을 써서 CPU를 나눠 쓰고,
- 네트워크(Network): 패킷으로 쪼개져 거친 도로를 달린 뒤,
- 렌더링(Rendering): 브라우저라는 화가를 만나 비로소 우리 눈앞에 나타났다.
처음엔 그저 취업을 위해 달달 외웠던 지식들이었다. 하지만 실무의 에러들과 부딪히며 다시 들여다본 CS(컴퓨터 공학)는, 죽어있는 글자가 아니라 내 코드를 지탱하는 단단한 지반이었다.
이제 기초 공사는 끝났다. 단단해진 지반 위에 본격적으로 나만의 성을 쌓을 시간이다. 다음 시리즈 [Monolith Builder]에서는, 내가 실무에서 겪었던 Spring Boot와 Vue.js를 활용한 웹 애플리케이션 구축기를 다룰 예정이다. ‘이론’이 ‘실전’이 되는 그 과정을 기대해 주기 바란다.