브라우저 렌더링 원리 – HTML이 화면이 되기까지 과정 이해하기

1. 브라우저가 URL을 입력받으면 무슨 일이 일어나는가?

주소창에 URL을 입력하고 엔터를 누르는 순간부터 화면에 내용이 표시되기까지, 브라우저 안에서는 굉장히 많은 일이 일어납니다.

DNS 조회로 IP 주소를 찾고, TCP 연결을 맺고, HTTP 요청을 보내고, 응답을 받는 과정이 끝나면 이제 브라우저가 받은 HTML 파일을 화면으로 그리는 렌더링(Rendering) 단계가 시작됩니다.

이 렌더링 과정을 이해하면 왜 특정 코드 작성 방식이 성능에 영향을 주는지 명확하게 알 수 있습니다.

2. DOM 트리 생성 – HTML 파싱

브라우저가 HTML 파일을 받으면 가장 먼저 **파싱(Parsing)**을 시작합니다. HTML 코드를 위에서 아래로 순서대로 읽으면서 각 태그를 분석합니다.

파싱 결과로 DOM(Document Object Model) 트리가 만들어집니다. DOM 트리는 HTML의 계층 구조를 표현하는 트리 형태의 데이터 구조입니다. <html> 태그가 최상위 노드가 되고 <head>, <body> 같은 자식 요소들이 하위 노드로 연결됩니다.

JavaScript에서 document.getElementById() 같은 메서드로 HTML 요소에 접근할 수 있는 이유가 바로 DOM이 이 구조를 제공하기 때문입니다.

3. CSSOM 트리 생성 – CSS 파싱

HTML 파싱 중 <link rel="stylesheet"> 태그를 만나면 브라우저는 CSS 파일을 요청합니다. CSS 파일이 도착하면 CSS를 파싱해 CSSOM(CSS Object Model) 트리를 만듭니다.

CSSOM은 각 CSS 선택자가 어떤 스타일을 가지는지 트리 형태로 정리한 것입니다.

중요한 점은 CSS는 렌더링 차단 리소스라는 것입니다. 브라우저는 CSSOM이 완성되기 전까지 렌더 트리 생성을 시작하지 않습니다. CSS 파일이 크거나 느리게 로딩되면 화면에 내용이 표시되는 시간이 그만큼 늦어집니다.

4. 렌더 트리 생성 – DOM과 CSSOM의 결합

DOM 트리와 CSSOM 트리가 모두 준비되면 이 둘을 결합해 **렌더 트리(Render Tree)**를 만듭니다.

렌더 트리는 실제로 화면에 표시되는 요소들만 포함합니다. display: none으로 숨겨진 요소는 렌더 트리에 포함되지 않습니다. 반면 visibility: hidden으로 숨겨진 요소는 공간은 차지하기 때문에 렌더 트리에 포함됩니다.

각 노드에는 적용될 CSS 스타일이 함께 포함됩니다.

5. 레이아웃(Reflow) – 요소의 크기와 위치 계산

렌더 트리가 완성되면 브라우저는 각 요소의 정확한 크기와 위치를 계산합니다. 이 단계를 레이아웃(Layout) 또는 Reflow라고 합니다.

브라우저 창의 크기, 각 요소의 width/height, margin, padding, position 등을 고려해 모든 요소가 어디에, 얼마나 크게 표시될지를 계산합니다.

레이아웃은 비용이 큰 작업입니다. JavaScript로 요소의 크기나 위치를 변경하면 Reflow가 다시 발생합니다. 특히 여러 요소를 반복해서 변경하면 Reflow가 반복 발생해 성능이 저하됩니다.

6. 페인팅(Paint) – 화면에 픽셀 그리기

레이아웃 계산이 끝나면 실제로 화면에 픽셀을 그리는 페인팅(Painting) 단계가 시작됩니다.

텍스트, 색상, 이미지, 그림자, 테두리 등 모든 시각적 요소를 픽셀로 그립니다. 브라우저는 페이지를 여러 레이어로 나눠 독립적으로 그린 뒤 합성(Compositing)합니다.

CSS의 opacity나 transform 같은 속성을 사용하면 GPU 가속을 활용해 페인팅과 합성이 더 빠르게 이루어집니다. 그래서 애니메이션을 만들 때 left나 top 대신 transform을 사용하는 것이 성능상 유리합니다.

7. 렌더링을 방해하는 요소들

렌더링 과정에서 병목이 되는 주요 요소들을 정리합니다.

렌더링 차단 CSS <head>에 있는 CSS 파일은 모두 로딩되기 전까지 렌더 트리 생성을 차단합니다. 크리티컬 CSS(첫 화면 렌더링에 필요한 CSS)를 <style> 태그로 인라인 삽입하고, 나머지 CSS는 비동기로 로드하면 개선됩니다.

파서 차단 JavaScript <head>에 있는 <script> 태그는 HTML 파싱 자체를 중단시킵니다. JS 파일이 도착하고 실행될 때까지 HTML 파싱이 멈춥니다. 이를 방지하기 위해 defer 또는 async 속성을 사용합니다.

defer는 HTML 파싱이 완료된 후 JS를 실행합니다. async는 JS 파일이 도착하는 즉시 실행합니다.

잦은 Reflow 유발 JavaScript로 요소의 크기나 위치를 자주 변경하면 Reflow가 반복 발생합니다. 변경 사항을 한 번에 모아서 적용하거나, CSS 클래스를 토글하는 방식으로 최소화합니다.

8. 정리 및 다음 단계

오늘 배운 핵심을 정리합니다.

  • 브라우저 렌더링은 DOM 생성 → CSSOM 생성 → 렌더 트리 → 레이아웃 → 페인팅 순서로 진행됩니다.
  • CSS는 렌더링 차단 리소스로, CSSOM이 완성될 때까지 렌더 트리 생성이 대기합니다.
  • <head><script>는 HTML 파싱을 중단시키므로 defer 또는 async를 사용합니다.
  • 애니메이션에는 left/top 대신 transform을 사용하면 GPU 가속으로 성능이 향상됩니다.

다음 글에서는 CSS와 JavaScript 로딩을 최적화해 렌더 블로킹을 줄이는 방법을 알아보겠습니다.

댓글 남기기

광고 차단 알림

광고 클릭 제한을 초과하여 광고가 차단되었습니다.

단시간에 반복적인 광고 클릭은 시스템에 의해 감지되며, IP가 수집되어 사이트 관리자가 확인 가능합니다.