castle.log
BlogWorkHistory
GitHub

브라우저 렌더링 과정 정리

2026년 05월 23일  13일 전
Browser
Rendering
Performance
브라우저 렌더링 과정 정리

핵심 요약

  • 브라우저 렌더링은 HTML, CSS, JavaScript를 읽어서 사용자가 보는 화면으로 바꾸는 과정입니다.
  • 큰 흐름은 HTML 파싱 → DOM 생성 → CSS 파싱 → CSSOM 생성 → Render Tree 생성 → Layout → Paint → Composite 순서로 보면 됩니다.
  • 화면 구조나 스타일이 바뀌면 브라우저는 필요한 만큼 다시 계산하고 다시 그립니다. 이때 자주 나오는 개념이 reflowrepaint입니다.
  • 이 과정을 알고 있으면 “왜 이 화면이 느리지?”, “왜 이 애니메이션이 버벅이지?” 같은 문제를 훨씬 잘 추적할 수 있습니다.

브라우저 렌더링 과정이란?

브라우저 렌더링 과정은 서버에서 받은 HTML, CSS, JavaScript를 해석해서 실제 화면에 보여주는 과정입니다.

겉으로 보면 브라우저가 HTML 파일을 받아서 바로 화면에 띄우는 것처럼 보이지만, 내부에서는 꽤 많은 일을 합니다.
HTML을 읽어서 문서 구조를 만들고, CSS를 읽어서 스타일 규칙을 정리하고, 각 요소가 어디에 얼마나 큰 크기로 배치될지 계산한 다음, 마지막으로 픽셀을 그립니다.

프론트엔드에서 이 과정을 알아야 하는 이유는 단순합니다.
DOM을 자주 바꾸거나, 레이아웃에 영향을 주는 CSS를 많이 변경하거나, 무거운 애니메이션을 만들면 화면이 느려질 수 있기 때문입니다.

전체 흐름

브라우저가 화면을 그릴 때는 보통 아래 흐름으로 이해하면 됩니다.

  1. HTML을 읽고 DOM Tree를 만든다.
  2. CSS를 읽고 CSSOM Tree를 만든다.
  3. DOM과 CSSOM을 합쳐 Render Tree를 만든다.
  4. 각 요소의 위치와 크기를 계산한다. 이 단계가 Layout이다.
  5. 색상, 배경, 텍스트, 이미지 등을 실제로 그릴 준비를 한다. 이 단계가 Paint다.
  6. 여러 레이어를 합쳐 최종 화면을 만든다. 이 단계가 Composite다.

면접에서는 이 순서를 그대로 외우기보다, “구조를 만들고, 스타일을 붙이고, 위치를 계산하고, 그리고, 합성한다” 정도로 이해해두면 말하기가 훨씬 편합니다.

HTML 파싱과 DOM 생성

브라우저는 HTML 문서를 위에서 아래로 읽으면서 태그를 해석합니다.
그리고 그 결과를 트리 구조인 DOM(Document Object Model) 으로 만듭니다.

예를 들어 이런 HTML이 있다고 해보겠습니다.

<body>
  <h1>Hello</h1>
  <p>Browser Rendering</p>
</body>

브라우저는 body 아래에 h1, p가 있는 구조로 DOM Tree를 만듭니다.
우리가 JavaScript에서 document.querySelector()appendChild() 같은 API로 조작하는 대상도 바로 이 DOM입니다.

즉, DOM은 HTML 문자열을 브라우저가 다루기 쉬운 객체 구조로 바꿔놓은 것이라고 볼 수 있습니다.

CSS 파싱과 CSSOM 생성

CSS도 HTML처럼 브라우저가 파싱합니다.
이때 만들어지는 구조가 CSSOM(CSS Object Model) 입니다.

CSSOM은 “어떤 요소에 어떤 스타일이 적용되는지”를 계산하기 위해 필요합니다.
CSS에는 상속, 명시도, 우선순위, 미디어 쿼리 같은 규칙이 있기 때문에 브라우저가 이를 정리해두어야 합니다.

h1 {
  color: blue;
  font-size: 24px;
}

이 CSS를 읽으면 브라우저는 h1에 적용할 색상과 글자 크기 정보를 CSSOM 안에 정리합니다.

여기서 중요한 점은 DOM만 있어서는 화면을 제대로 그릴 수 없다는 것입니다.
문서 구조는 DOM이 알려주고, 화면에 어떻게 보일지는 CSSOM이 알려줍니다.

Render Tree 생성

브라우저는 DOM과 CSSOM을 합쳐서 Render Tree를 만듭니다.
Render Tree는 실제 화면에 그릴 요소만 모아둔 트리입니다.

예를 들어 display: none이 적용된 요소는 화면에 그리지 않으므로 Render Tree에 들어가지 않습니다.
반면 visibility: hidden은 보이지는 않지만 공간은 차지할 수 있기 때문에 Layout 계산에는 영향을 줄 수 있습니다.

쉽게 말하면 DOM은 문서 전체 구조이고, Render Tree는 그중에서 “진짜 화면에 그릴 대상”에 가깝습니다.

Layout

Layout 단계에서는 각 요소의 위치와 크기를 계산합니다.

예를 들어 어떤 박스의 너비가 50%라면, 브라우저는 부모 요소의 크기를 보고 실제 픽셀 너비를 계산해야 합니다.
flex, grid, vh, vw 같은 값도 마찬가지입니다. 코드에는 상대적인 값으로 적혀 있지만, 화면에 그리려면 결국 실제 좌표와 크기가 필요합니다.

Layout은 비용이 큰 작업이 될 수 있습니다.
특히 한 요소의 크기 변화가 부모나 형제 요소에 영향을 주면, 브라우저는 꽤 넓은 범위의 위치와 크기를 다시 계산해야 할 수 있습니다.

Paint

Paint 단계에서는 Layout에서 계산한 위치와 크기를 바탕으로 색상, 배경, 텍스트, 이미지, 그림자 같은 시각 요소를 그립니다.

예를 들어 color, background-color, box-shadow 같은 속성이 바뀌면 요소의 크기나 위치는 그대로일 수 있습니다.
이 경우 Layout까지 다시 할 필요는 없지만, 화면에 보이는 색이나 그림자는 다시 그려야 하므로 Paint가 발생할 수 있습니다.

Composite

Composite 단계에서는 여러 레이어를 합쳐 최종 화면을 만듭니다.

브라우저는 모든 요소를 한 장의 종이에 한 번에 그리는 방식으로만 처리하지 않습니다.
필요에 따라 화면을 여러 레이어로 나누고, 마지막에 이 레이어들을 합성해서 사용자에게 보여줍니다.

transform, opacity 같은 속성은 Layout이나 Paint를 크게 건드리지 않고 Composite 단계에서 처리될 수 있는 경우가 많습니다.
그래서 위치 이동 애니메이션을 만들 때 top, left보다 transform: translate()를 더 자주 권장합니다.

reflow와 repaint

reflow

reflow는 Layout을 다시 계산하는 작업입니다.
요소의 위치나 크기가 바뀌면 브라우저는 “이 요소가 이제 어디에 있어야 하지?”를 다시 계산해야 합니다.

예를 들어 이런 변경은 reflow를 일으킬 수 있습니다.

  • 요소 추가 또는 삭제
  • 너비, 높이, margin, padding 변경
  • 폰트 크기 변경
  • 브라우저 창 크기 변경
  • display 값 변경

reflow는 보통 비용이 큰 편입니다.
위치와 크기를 다시 계산하다 보면 주변 요소까지 영향을 받을 수 있기 때문입니다.

repaint

repaint는 위치나 크기는 그대로인데, 눈에 보이는 스타일만 다시 그리는 작업입니다.

예를 들어 이런 변경은 repaint를 일으킬 수 있습니다.

  • 글자 색 변경
  • 배경색 변경
  • visibility 변경
  • 그림자 변경

repaint는 reflow보다 가벼운 경우가 많지만, 화면의 큰 영역을 다시 그려야 하거나 요소가 많으면 이것도 성능에 영향을 줄 수 있습니다.

JavaScript가 렌더링에 미치는 영향

JavaScript는 DOM과 CSSOM을 바꿀 수 있기 때문에 렌더링에 직접 영향을 줍니다.

특히 HTML을 파싱하는 중에 일반 <script>를 만나면 브라우저는 스크립트를 다운로드하고 실행할 때까지 HTML 파싱을 멈출 수 있습니다.
스크립트가 DOM을 조작할 수도 있기 때문에, 브라우저 입장에서는 일단 실행 결과를 확인해야 하는 것입니다.

그래서 실무에서는 렌더링 차단을 줄이기 위해 이런 방식을 자주 사용합니다.

  • 중요하지 않은 스크립트에는 defer 또는 async를 사용한다.
  • DOM 조작은 가능하면 한 번에 모아서 처리한다.
  • 반복문 안에서 레이아웃을 읽고 쓰는 작업을 섞지 않는다.
  • 애니메이션은 requestAnimationFrame을 활용한다.

예를 들어 스타일을 바꾼 직후 offsetWidthgetBoundingClientRect()를 읽으면, 브라우저가 최신 레이아웃 값을 알려주기 위해 강제로 Layout을 다시 계산할 수 있습니다.
이런 상황을 반복하면 화면이 버벅일 수 있습니다.

렌더링 성능 최적화 포인트

  • DOM 변경은 가능하면 모아서 처리합니다.
  • 애니메이션에는 top, left보다 transform, opacity를 먼저 고려합니다.
  • DOM 구조를 불필요하게 깊고 복잡하게 만들지 않습니다.
  • 큰 이미지나 웹폰트는 로딩 방식을 신경 씁니다.
  • 화면 밖 콘텐츠는 필요할 때 렌더링하는 방식도 고려합니다.
  • 레이아웃 값을 읽는 작업과 스타일을 쓰는 작업을 반복적으로 섞지 않습니다.

면접 답변 예시

브라우저 렌더링 과정은 HTML, CSS, JavaScript를 해석해서 화면에 보여주는 과정입니다.
먼저 HTML을 파싱해서 DOM Tree를 만들고, CSS를 파싱해서 CSSOM Tree를 만듭니다. 그다음 DOM과 CSSOM을 합쳐 실제로 화면에 그릴 Render Tree를 만들고, 각 요소의 위치와 크기를 계산하는 Layout 단계를 거칩니다. 이후 색상, 배경, 텍스트 등을 그리는 Paint 단계가 있고, 마지막으로 여러 레이어를 합성하는 Composite 단계를 통해 최종 화면이 만들어집니다.

성능 관점에서는 reflow와 repaint를 같이 설명하면 좋습니다.
요소의 크기나 위치가 바뀌면 Layout을 다시 계산하는 reflow가 발생할 수 있고, 색상처럼 시각적인 스타일만 바뀌면 repaint가 발생할 수 있습니다. reflow는 상대적으로 비용이 크기 때문에 DOM 조작을 줄이고, 애니메이션에서는 transform, opacity 같은 속성을 활용하는 것이 도움이 됩니다.

장점

  • 화면이 느려질 때 어디서 비용이 생기는지 추적하기 쉬워집니다.
  • DOM 조작, CSS 변경, 애니메이션을 만들 때 더 나은 선택을 할 수 있습니다.
  • 면접에서 단순 암기보다 “브라우저가 화면을 만드는 흐름”을 설명할 수 있습니다.

단점

  • 브라우저 엔진마다 내부 최적화 방식이 조금씩 다를 수 있습니다.
  • 실제 성능 문제는 렌더링뿐 아니라 네트워크, JavaScript 실행 시간, 이미지, 폰트 로딩도 함께 봐야 합니다.

주의사항 / 실무 팁

  • display: none은 Render Tree에서 제외되지만, visibility: hidden은 공간을 차지할 수 있다는 차이를 기억해두면 좋습니다.
  • Layout을 유발하는 속성과 Paint만 유발하는 속성의 차이를 알아두면 성능 최적화에 도움이 됩니다.
  • 애니메이션 성능이 중요하다면 transform, opacity 중심으로 구현하는 방식을 먼저 떠올려보세요.
  • 성능 최적화는 감으로만 하지 말고, Chrome DevTools의 Performance 탭으로 실제 병목을 확인하는 습관이 중요합니다.
이전 게시글SSR과 CSR 정리
다음 게시글React Error Boundary 정리