Beyond Frontend

"웹 성능 최적화의 기본기": 브라우저 렌더링 과정을 이해하는 5단계 본문

IT Insights

"웹 성능 최적화의 기본기": 브라우저 렌더링 과정을 이해하는 5단계

dietgogo 2025. 8. 31. 13:53

서론: 왜 브라우저 렌더링을 알아야 할까?

사용자가 웹사이트에서 스크롤할 때마다 화면이 뚝뚝 끊기거나, 버튼을 클릭해도 한참 뒤에 반응하는 답답한 경험. 누구나 한 번쯤 겪어봤을 겁니다. 프론트엔드 개발자로서 이런 '버벅임(Jank)'은 피하고 싶은 숙적과도 같죠. 멋진 기능을 구현하는 것도 중요하지만, 부드럽고 쾌적한 사용자 경험을 제공하는 것은 그 무엇보다 우선되어야 합니다. 그리고 그 열쇠는 바로 브라우저가 화면을 그리는 방식, 즉 '렌더링 과정'을 이해하는 데 있습니다.

마치 마법처럼 보이는 이 과정은 사실 매우 체계적인 파이프라인으로 이루어져 있습니다. 우리가 작성한 HTML, CSS, JavaScript 코드가 어떻게 실제 픽셀로 변환되는지 알게 되면, 어디서 병목이 발생하고 어떻게 개선할 수 있는지에 대한 명확한 그림을 그릴 수 있습니다. 이 글에서는 브라우저 렌더링의 5가지 핵심 단계를 살펴보고, 이를 바탕으로 실무에 바로 적용할 수 있는 성능 최적화 전략까지 함께 알아보겠습니다.

 

브라우저 렌더링 파이프라인: 5단계 핵심 과정

브라우저가 코드를 화면에 그리기까지의 과정을 '중요 렌더링 경로(Critical Rendering Path)'라고 부릅니다. 이 경로는 여러 단계로 나뉘며, 각 단계는 이전 단계의 결과물을 입력으로 사용합니다. 지금부터 그 핵심 5단계를 하나씩 파헤쳐 보겠습니다.

1단계: 파싱 (Parsing) - DOM과 CSSOM 트리 구축

모든 것은 브라우저가 서버로부터 받은 HTML과 CSS 파일을 '이해'하는 것에서 시작됩니다. 브라우저는 텍스트로 된 HTML 코드를 읽어들여 객체 모델로 변환하는데, 이것이 바로 **문서 객체 모델(DOM, Document Object Model)**입니다. DOM은 문서의 구조와 내용을 담은 트리 형태로, JavaScript가 문서에 접근하고 조작할 수 있는 통로가 됩니다. (MDN - How browsers work 참조)

동시에 브라우저는 CSS 파일도 파싱하여 **CSS 객체 모델(CSSOM, CSS Object Model)**을 만듭니다. CSSOM은 각 요소에 어떤 스타일 규칙이 적용되어야 하는지에 대한 정보를 담은 트리입니다. div는 파란색, .title은 24px 폰트 크기 같은 정보들이 여기에 정리됩니다.

2단계: 스타일 (Style) - 렌더 트리 생성

이제 브라우저는 독립적으로 만들어진 DOM 트리와 CSSOM 트리를 결합하여 **렌더 트리(Render Tree)**를 구축합니다. 이 단계에서 중요한 점은 렌더 트리가 '화면에 그려질 요소들'만 포함한다는 것입니다. 예를 들어, <head> 태그나 display: none; 스타일이 적용된 요소는 최종 결과물에 보이지 않으므로 렌더 트리에서 제외됩니다. 반면, visibility: hidden;이 적용된 요소는 공간은 차지하되 보이지만 않기 때문에 렌더 트리에 포함됩니다. (web.dev - Render-tree Construction 참조)

3단계: 레이아웃 (Layout) - 요소의 위치와 크기 계산

렌더 트리가 만들어졌지만, 아직 각 요소가 화면의 어디에, 어떤 크기로 위치할지는 정해지지 않았습니다. '레이아웃' 단계에서 브라우저는 뷰포트(viewport)를 기준으로 각 요소의 정확한 위치와 크기, 즉 기하학적 정보(geometry)를 계산합니다. width: 50%와 같은 상대적인 값들이 이 단계에서 500px과 같은 실제 픽셀 값으로 변환됩니다. 이 과정을 '리플로우(Reflow)'라고도 부릅니다.

4단계: 페인트 (Paint) - 화면에 픽셀 채우기

레이아웃 계산이 끝나면, 브라우저는 드디어 화면에 그림을 그릴 준비를 마칩니다. '페인트' 단계에서는 렌더 트리의 각 노드를 화면의 실제 픽셀로 변환하는 작업, 즉 '래스터화(Rasterizing)'가 일어납니다. 텍스트, 색상, 이미지, 그림자 등 계산된 모든 시각적 요소들이 이 단계에서 그려집니다. 성능을 위해 브라우저는 화면을 여러 개의 '레이어(Layer)'로 나누어 그릴 수 있습니다.

5단계: 합성 (Compositing) - 레이어 결합 및 최종 출력

페인트 단계에서 여러 레이어로 나뉘어 그려진 결과물들은 '합성' 단계에서 하나로 합쳐져 최종 화면을 만듭니다. 특정 CSS 속성(transform, opacity 등)을 사용하면 해당 요소는 별도의 레이어로 분리되어 처리될 수 있습니다. 이렇게 하면 해당 레이어만 독립적으로 움직이거나 변경될 수 있어, 전체 화면을 다시 그리는(Repaint) 비용을 줄이고 GPU 가속을 통해 성능을 크게 향상시킬 수 있습니다.

 

실전! 렌더링 성능 최적화 전략

렌더링 과정을 이해했다면, 이제 각 단계에서 성능을 저해하는 요인을 찾아 개선할 차례입니다. 목표는 비싼 비용이 드는 '레이아웃'과 '페인트'를 최대한 피하고, 가벼운 '합성' 단계만으로 변화를 처리하는 것입니다.

 

레이아웃(리플로우) 최소화하기

리플로우는 렌더링 파이프라인에서 가장 비용이 큰 작업 중 하나입니다. 한 요소의 크기나 위치가 바뀌면, 그 주변 요소들은 물론 자식과 부모 요소까지 연쇄적으로 영향을 받아 재계산이 필요할 수 있기 때문입니다. (공삼 - 리플로우와 리페인트 참조)

리플로우를 유발하는 대표적인 속성은 width, height, margin, padding, top, left 등 기하학적 변화를 일으키는 것들입니다. 애니메이션을 구현할 때 이런 속성을 직접 변경하는 대신, transform: scale()이나 transform: translate()를 사용하세요. transform 속성은 레이아웃에 영향을 주지 않고 합성 단계에서 처리되므로 훨씬 효율적입니다.

/* ❌ Bad: Reflow를 유발합니다 */
.box {
  transition: width 0.3s;
}
.box:hover {
  width: 200px;
}

/* ✅ Good: Compositing만으로 처리됩니다 */
.box {
  transition: transform 0.3s;
}
.box:hover {
  transform: scale(1.2);
}

또한, JavaScript로 여러 스타일을 변경할 때는 한 번에 처리하는 것이 좋습니다. 여러 번에 걸쳐 DOM 요소를 변경하면 그만큼 리플로우가 여러 번 발생할 수 있습니다. 스타일 변경이 필요하다면 클래스를 한 번에 교체하는 방식을 권장합니다.

 

페인트와 합성 단계 최적화하기

background-color나 color처럼 기하학적 변화 없이 시각적 변화만 있는 속성은 리플로우는 건너뛰고 페인트 단계만 유발합니다. 리플로우보다는 낫지만, 이 역시 비용이 발생합니다. 가장 좋은 시나리오는 페인트마저 건너뛰고 합성 단계만으로 처리하는 것입니다.

앞서 언급한 transform과 opacity가 바로 합성 단계만 유발하는 대표적인 속성입니다. 브라우저는 이 속성들이 변경될 것을 예상하고 해당 요소를 별도의 레이어로 승격시켜 GPU가 처리하도록 합니다. 이를 통해 메인 스레드의 부담을 덜고 부드러운 애니메이션을 구현할 수 있습니다.

만약 특정 요소에 애니메이션이 적용될 것을 미리 알고 있다면, will-change 속성을 사용하여 브라우저에게 힌트를 줄 수 있습니다. 브라우저는 이 힌트를 보고 해당 요소를 미리 별도의 레이어로 분리하는 등 최적화를 준비할 수 있습니다. (MDN - will-change 참조)

.animating-element {
  /* 브라우저에게 transform 속성이 곧 변경될 것이라고 알림 */
  will-change: transform;
}
주의: will-change는 강력한 도구지만 남용해서는 안 됩니다. 이 속성은 브라우저가 추가적인 메모리를 사용하도록 만들기 때문에, 꼭 필요한 곳에, 그리고 애니메이션이 시작되기 직전에 적용하고 끝난 후에는 제거하는 것이 좋습니다. 성능 문제를 해결하기 위한 최후의 수단으로 생각하세요. (MDN - will-change Warning 참조)

 

마치며: 성능은 디테일에서 시작된다

지금까지 브라우저가 화면을 그리는 5단계 과정과 이를 기반으로 한 최적화 전략을 살펴보았습니다. 복잡해 보일 수 있지만 핵심은 간단합니다. '리플로우 → 리페인트 → 합성' 순으로 비용이 비싸다는 사실을 기억하고, 가능한 한 파이프라인의 뒷단에서 변화를 처리하도록 코드를 작성하는 것입니다.

웹 성능 최적화는 단순히 코드를 줄이는 것을 넘어, 브라우저의 작동 원리를 깊이 이해하고 그에 맞춰 소통하는 과정입니다. 오늘 배운 내용을 바탕으로 크롬 개발자 도구의 'Performance' 탭을 열어 여러분의 웹사이트가 어떻게 렌더링되고 있는지 직접 분석해보는 것은 어떨까요? 작은 디테일의 변화가 사용자 경험에 큰 차이를 만들어낼 수 있습니다.