웹 페이지 렌더링 과정(DOM, CSSOM, Render Tree)

Jseok·2025년 10월 26일

우리는 일상 속에서 정말 많은 웹사이트에 접속하며 살아가고 있다. 링크만 클릭하면, 어느 곳에서나 어떤 기기로든 접속이 가능하다. 사용자의 입장에서는 간단한 과정처럼 보이지만, 실제로 그 뒤에서는 어떠한 과정이 이루어지는지 이 글에서 간단하게나마 알아보고자 한다.

1. 웹 페이지 렌더링이란?

웹 브라우저가 HTML, CSS, JavaScript와 같은 소스코드를 파싱하여 사용자가 볼 수 있는 시각적 웹 페이지로 변환하는 과정을 의미한다. 브라우저는 소스코드를 해석하여 텍스트의 크기, 색상, 레이아웃 등 화면에 보이는 모든 것을 계산하여 그려낸다. 쉽게 말해, 웹 페이지가 화면에 표시될 수 있도록 하는 과정이다.

이러한 렌더링 과정은 브라우저의 성능을 좌우하며, 이를 이해하면 웹 사이트의 성능을 최적화하고 UX를 개선할 수 있다.

2. 전체 렌더링 과정

브라우저의 렌더링 과정을 간단하게 그림으로 표현하면 위와 같다.
만약 이 과정을 크게 나눈다면 대략적으로 두 단계로 나눌 수 있다. 첫 번째 단계는 문서를 파싱해서 Render Tree를 만드는 과정이고, 두 번째는 이 Render Tree를 기반으로 브라우저가 렌더링을 수행하는 과정이다.

2-1. DOM이란?

가장 먼저 브라우저는 HTML 파일을 읽고 DOM 트리를 생성한다.
DOM이란 'Document Object Model'의 약자로, 그대로 해석하면 '문서 객체 모델'이다. 이를 이해하기 위해서는 '문서 구조'를 이해하면 좋다. 우리가 작성하는 HTML 문서에는 <head>, <body>, <p> 등 여러 태그가 문서의 구조를 이루고 있다. 이러한 HTML 요소의 계층, 구조를 반영하여 만든 객체를 DOM이라고 한다.

[DOM 구조]
DOM을 제대로 이해하기 위해서는 'Tree'라는 자료구조를 이해하면 좋다 DOM의 객체 구조는 '노드 트리'로 표현되기 때문이다. 이는 하나의 부모 줄기가 여러 자식 가지로 갈라지는 트리 형태를 의미한다. 예를 들자면 <html>이라는 부모 줄기에 <head>, <body> 등 다양한 자식 가지가 뻗어나가는 형태를 생각하면 된다.

[DOM과 JavaScript]
DOM은 JavaSript와 같은 프로그래밍 언어와 HTML로 구성된 웹페이지를 연결시켜주는 역할을 한다. DOM API를 통해 HTML 요소를 찾고, 수정하고 삭제하며 이벤트에 반응하는 등 웹페이지와 상호작용하는 여러 기능들을 구현할 수 있다.

요약하면, 페이지 컨텐츠는 DOM에 저장되고 JavaScript를 통해 접근하거나 조작할 수 있다.

[DOM이 생성되는 순서]

지금까지 이야기한 것처럼, HTML 문서는 HTML 파서에 의해 DOM으로 변환된다.

만약 파서가 DOM 생성 중간에 <script> 태그를 만난다면, 파서는 DOM 생성을 중단하고 JavaScript 엔진이 스크립트에 정의된 파일과 코드를 실행한다. 이 작업이 모두 끝나야만 다시 DOM 생성을 시작한다.

즉, 브라우저는 HTML과 JavaScript를 동시에 처리하지 않고 '동기적'으로 처리한다. 이는 <script> 태그 위치에 따라 DOM 생성이 느려질 수 있다는 의미이다. 따라서 <script> 태그는 HTML 문서 가장 하단에 넣거나, async, defer와 같은 속성들을 활용해서 최적화하는 것이 바람직하다.

2-2. CSSOM이란?

위에서 DOM을 먼저 알아봤기 때문에, CSSOM은 비교적 쉽게 이해할 수 있다.

HTML을 파싱해서 DOM을 생성했다면, 이번에는 CSS 파일을 파싱해서 CSSOM을 생성한다. CSSOM은 'CSS Object Model'의 약자로, CSS 스타일 정보를 트리 형태로 구조화한 것이다.

DOM을 사용해 JavaScript에서 문서의 구조와 내용을 읽고 수정할 수 있는 방식과 비슷하게, CSSOM을 활용하여 JavaScript에서 문서의 스타일을 읽고 수정할 수 있다.

2-3. Render Tree 생성

DOM과 CSSOM을 생성했다면, 브라우저는 이제 DOM과 CSSOM을 결합해 Render Tree를 생성한다. Render Tree는 화면에 표시될 요소들만 포함하고 있으며, 각 요소에 적용될 스타일과 위치에 대한 정보를 담고 있다.

화면에 표시할 요소들만 표현한다는 의미는, 예를 들자면 <script>, <meta> 처럼 화면에 렌더링 될 요소가 아닌 것들은 생략한다. 또한 일부 노드들은 CSS를 사용하여 숨겨지며, 이러한 요소 또한 Render Tree에서 생략된다. (display : none;)

최종적으로 렌더링할 노드들을 선별했다면, 표시된 각 노드에 적절하게 일치하는 CSSOM 규칙을 찾아 적용한 후 내보낸다.

2-4. Layout, Paint, Composite

이제 브라우저는 완성된 Render Tree를 기반으로 각 요소의 위치와 크기를 계산하는 Layout 단계에 들어간다. 이 과정에서 요소가 화면의 어디에 위치할지, 그리고 어떤 크기를 가질지 등을 결정한다.

Layout 단계 이후, paint 단계에서는 계산된 요소들의 위치와 크기를 참고하여 각 요소에 적용될 스타일 속성을 시각적으로 표현한다.

Composite 단계에서는, paint 과정에서 생성된 여러 개의 레이어들을 하나의 화면으로 결합한다. 특히 요소가 겹치는 경우에는 z-index, position 등의 속성을 고려해 겹침 순서를 처리한다.

3. 브라우저 렌더링 최적화

브라우저 렌더링 최적화 과정은 웹 사이트의 성능을 결정하는데 있어 핵심 요소이다. 만약 사용자가 웹 사이트에 접속했을 때, 렌더링 과정에서 발생하는 지연은 사용자 경험에 치명적이다. 뿐만 아니라 브라우저 렌더링 최적화를 통해 SEO도 긍정적인 영향을 줄 수 있다.
오늘은 전체적으로 어떤 방법이 있는지 알아보고, 다음 글에서 더 구체적으로 알아볼 것이다.

1. HTML 구조 간소화
불필요한 태그나 중첩된 구조를 줄여 브라우저가 DOM을 빠르게 처리할 수 있도록 하는 것이 좋다.

2. 리플로우와 리페인트 줄이기
리플로우와 리페인트를 최대한 줄이는 것은 브라우저 성능 최적화의 주요 대상이다. 이를 최소화하는 방법으로는 스타일 변경 최소화, 리플로우를 발생시키는 함수나 속성을 변수에 저장하여 여러번 호출 방지, DOM 접근 최소화 등이 있다.
아래 표는 리플로우, 리페인트를 발생시키는 원인을 정리한 것이다.

원인예시 코드비고
DOM 구조 변경element.appendChild()새 노드 추가 시 전체 레이아웃 재계산
스타일 변경element.style.width = "100px"위치·크기 변경 시 Reflow 발생
요소 크기 측정offsetWidthclientHeightgetComputedStyle()강제 Reflow(triggered layout)
윈도우 리사이즈window.resize전체 Layout 재계산

3. 이미지와 리소스 최적화
이미지는 파일 크기가 크기 때문에 로딩 속도에 큰 영향을 미친다. 사용자가 보지 않는 이미지를 미리 로드하면 불필요한 네트워크 요청과 자원 소비가 일어나므로, lazy loading을 적절히 사용하는 방법도 고려해보면 좋다.

4. JS 로드 방식 최적화
스크립트 파일이 로드되고 실행되는 방식 또한 페이지 렌더링 성능에 중요한 역할을 미친다. 위에서 잠깐 언급한 것처럼 async, defer 속성을 적절히 사용하면 최적화에 큰 도움이 된다. async 속성은 DOM 조작이 필요 없거나, 다른 스크립트에 의존하지 않는 독립적인 스크립트에 사용하고 defer 속성은 반대로 DOM을 조작해야 하거나 스크립트 간의 실행 순서가 중요한 경우에 권장되는 방식이다.

참고

https://developer.mozilla.org/ko/docs/conflicting/Web/API/Document_Object_Model_a0b90593de4c5cb214690e823be115a18d605d4bc7719ba296e212da2abe18ef
http://docs.tosspayments.com/resources/glossary/dom
https://bitsofco.de/what-exactly-is-the-dom/?utm_source=CSS-Weekly&utm_campaign=Issue-341&utm_medium=email&source=post_page-----7d72f85be01c---------------------------------------
https://web.dev/articles/critical-rendering-path/render-tree-construction?hl=ko
https://onlydev.tistory.com/9
https://binyard.me/javascript/basic/browser/js002
https://ko.javascript.info/script-async-defer
https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Lazy_loading
https://www.corewebvitals.io/pagespeed/async-vs-defer-javascript-and-core-web-vitals

0개의 댓글