크리티컬 렌더링 패스
1. 개요
1. 개요
크리티컬 렌더링 패스는 웹 브라우저가 서버로부터 HTML, CSS, 자바스크립트와 같은 리소스를 수신하여 최종적으로 화면에 픽셀로 변환하여 표시하기까지 거치는 일련의 필수적인 단계와 과정을 의미한다. 이 과정의 주요 목표는 사용자가 페이지의 초기 내용을 가능한 한 빠르게 볼 수 있도록 초기 렌더링의 속도를 최적화하는 것이다.
이 패스는 여러 핵심 단계로 구성된다. 먼저 HTML 파싱을 통해 DOM 트리를 구축하고, CSS 파싱을 통해 CSSOM 트리를 생성한다. 이후 이 두 트리를 결합하여 렌더 트리를 만들고, 각 요소의 정확한 위치와 크기를 계산하는 레이아웃 단계를 거친다. 마지막으로 계산된 정보를 바탕으로 실제 픽셀을 화면에 그리는 페인팅 단계가 수행된다.
이 과정에서 특정 리소스는 렌더링을 지연시키는 블로킹 리소스로 작용할 수 있다. 예를 들어, 렌더링 차단 CSS는 CSSOM이 완성되기 전까지 렌더 트리 생성이 차단되어 초기 렌더링을 지연시킨다. 또한 파싱 차단 자바스크립트는 DOM 트리 구축을 중단시킬 수 있다.
따라서 웹 성능 최적화의 핵심은 이 크리티컬 렌더링 패스를 분석하고 개선하는 데 있다. 최적화는 주로 초기 렌더링에 필수적인 중요 리소스를 식별하고, 이러한 리소스의 수를 의미하는 중요 경로 길이와 총 용량인 중요 바이트를 줄이는 방향으로 이루어진다.
2. 핵심 개념
2. 핵심 개념
2.1. DOM (Document Object Model)
2.1. DOM (Document Object Model)
DOM은 HTML 문서의 프로그래밍 인터페이스이다. 브라우저가 HTML 코드를 수신하면, 이를 바탕으로 DOM 트리를 구축하는 것이 크리티컬 렌더링 패스의 첫 번째 핵심 단계이다. 이 과정은 파싱이라고 하며, HTML의 태그와 내용을 분석하여 계층적인 트리 구조의 객체 모델로 변환한다. 이렇게 생성된 DOM은 문서의 논리적 구조를 나타내며, 이후 JavaScript가 문서의 내용, 구조, 스타일을 동적으로 조작할 수 있는 기반이 된다.
DOM 트리 구축은 일반적으로 순차적으로 진행되지만, 파싱 차단 JavaScript를 만나면 중단될 수 있다. 스크립트 태그를 만난 HTML 파서는 해당 스크립트의 다운로드와 실행이 완료될 때까지 DOM 구축을 일시 중지한다. 이는 스크립트가 아직 구축되지 않은 DOM 요소를 조작할 가능성이 있기 때문이다. 따라서 JavaScript 파일의 배치와 로딩 방식은 초기 DOM 생성 속도에 직접적인 영향을 미친다.
완성된 DOM 트리는 문서의 모든 요소와 그 속성, 텍스트 콘텐츠를 노드로 포함한다. 이 트리는 이후 CSSOM 트리와 결합되어 렌더 트리를 형성하는 데 사용된다. 효율적인 DOM 구조를 설계하고, 불필요하게 깊은 중첩을 피하며, 파싱 차단 JavaScript의 영향을 최소화하는 것은 크리티컬 렌더링 패스를 최적화하는 기본적인 방법이다.
2.2. CSSOM (CSS Object Model)
2.2. CSSOM (CSS Object Model)
CSSOM은 CSS 코드가 브라우저에 의해 해석되고 구조화된 객체 모델이다. HTML이 DOM 트리로 변환되는 것과 유사하게, 브라우저는 외부 CSS 파일, 내부 <style> 블록, 그리고 인라인 스타일을 읽어 CSS 규칙과 스타일을 이해할 수 있는 트리 형태의 데이터 구조로 변환한다. 이 과정을 CSS 파싱이라고 한다. CSSOM은 각 노드에 적용될 최종 스타일 값을 계산하는 스타일 규칙의 맵 역할을 하며, 이는 이후 렌더 트리를 생성하는 데 필수적인 입력 자료가 된다.
CSSOM의 생성은 렌더링 차단 리소스로 간주된다. 브라우저는 렌더 트리를 구성하기 위해 DOM과 CSSOM이 모두 필요하기 때문에, CSS 파일을 다운로드하고 파싱하여 CSSOM 트리를 완성하기 전까지는 렌더링을 진행할 수 없다. 이 때문에 <head> 섹션에 배치된 외부 스타일시트는 초기 페이지 렌더링을 지연시키는 주요 원인이 될 수 있다. 이러한 특성은 크리티컬 렌더링 패스의 핵심 개념인 렌더링 차단 CSS를 설명하는 근간이 된다.
CSSOM은 또한 캐스케이딩과 상속 규칙을 적용하여 각 DOM 요소에 대한 최종 스타일을 결정한다. 이 계산 과정은 상위 요소에서 하위 요소로, 그리고 명시도에 따라 스타일이 어떻게 적용될지를 해결한다. 완성된 CSSOM 트리는 DOM 트리와 결합되어, 화면에 실제로 그려질 요소와 그 스타일만을 포함하는 렌더 트리를 형성한다. 따라서 CSSOM 구축의 효율성은 전체 페이지의 시각적 완성 속도에 직접적인 영향을 미친다.
2.3. 렌더 트리 (Render Tree)
2.3. 렌더 트리 (Render Tree)
렌더 트리는 DOM 트리와 CSSOM 트리를 결합하여 생성되는 자료 구조이다. 이 트리는 실제로 화면에 렌더링될 노드들만을 포함하며, 예를 들어 <head> 섹션의 요소나 display: none 속성이 적용된 요소와 같은 시각적으로 보이지 않는 요소는 제외된다. 렌더 트리의 목적은 페이지의 시각적 구조를 계산하는 데 필요한 입력을 제공하는 것이다.
렌더 트리 구축은 DOM 트리와 CSSOM 트리가 모두 준비된 후에 시작된다. 브라우저는 각각의 DOM 노드에 대해 대응하는 CSSOM 스타일 규칙을 찾아 적용하고, 그 결과로 스타일이 지정된 시각적 객체를 생성한다. 이 과정은 렌더링 엔진에 의해 수행되며, 최종적으로는 화면에 그려질 모든 요소의 콘텐츠와 스타일 정보를 담게 된다.
렌더 트리는 이후 레이아웃 단계의 기초가 된다. 레이아웃 단계에서는 각 노드의 정확한 위치와 크기를 픽셀 단위로 계산하는데, 이 계산은 렌더 트리에 포함된 모든 노드의 기하학적 정보를 바탕으로 이루어진다. 따라서 렌더 트리의 구조와 복잡성은 페이지의 레이아웃 계산 성능에 직접적인 영향을 미친다.
렌더 트리 생성은 렌더링 차단 CSS나 파싱 차단 JavaScript와 같은 블로킹 리소스에 의해 지연될 수 있다. CSSOM이 완성되지 않으면 렌더 트리를 만들 수 없기 때문에, 스타일시트는 중요 리소스로 간주된다. 효율적인 렌더 트리 구축을 위해서는 불필요한 노드 깊이를 줄이고, 복잡한 CSS 선택자 사용을 피하는 등의 최적화가 필요하다.
2.4. 레이아웃 (Layout, Reflow)
2.4. 레이아웃 (Layout, Reflow)
레이아웃은 렌더 트리가 생성된 후 수행되는 단계로, 각 노드의 정확한 위치와 크기를 계산하는 과정이다. 이 과정은 때로 리플로우라고도 불리며, 브라우저가 화면에 표시될 모든 요소의 기하학적 속성(좌표, 너비, 높이 등)을 결정한다. 레이아웃은 뷰포트의 크기와 디바이스의 픽셀 밀도와 같은 외부 조건에 따라 결과가 달라질 수 있다.
레이아웃 계산은 렌더 트리의 루트부터 시작하여 모든 자식 노드를 순회하며 진행된다. 이 과정에서 CSS 박스 모델 규칙이 적용되고, 상대적 단위는 절대적 픽셀 값으로 변환되며, 플렉스박스나 그리드 레이아웃과 같은 복잡한 레이아웃 모델의 계산이 수행된다. 계산이 완료되면 각 요소는 화면 상의 정확한 좌표와 치수를 가지게 되어, 이후 페인팅 단계에서 픽셀로 채워질 준비를 마친다.
자바스크립트에 의한 DOM 조작이나 CSS 속성 변경은 종종 리플로우를 유발한다. 예를 들어, 요소의 너비나 높이를 변경하거나, 폰트 크기를 조정하거나, 윈도우 크기를 조절하면 브라우저는 변경의 영향을 받는 모든 요소의 레이아웃을 다시 계산해야 한다. 이 리플로우는 추가적인 페인트 과정을 필요로 하므로, 과도하게 발생하면 성능 저하의 주요 원인이 된다.
따라서 웹 성능 최적화를 위해서는 불필요한 리플로우를 최소화하는 것이 중요하다. 일반적인 기법으로는 CSS를 상단에 배치하여 초기 렌더링 시 올바른 레이아웃 계산을 보장하거나, 자바스크립트의 스타일 변경을 배치 처리하여 레이아웃 스래싱을 방지하는 방법 등이 있다.
2.5. 페인팅 (Painting)
2.5. 페인팅 (Painting)
페인팅은 렌더 트리와 레이아웃 단계를 거쳐 계산된 모든 시각적 요소를 실제 화면의 픽셀로 변환하여 그리는 과정이다. 이 단계는 때로 래스터화라고도 불리며, 브라우저의 렌더링 엔진이 각 요소의 배경, 테두리, 텍스트, 그림자 등 모든 시각적 스타일 속성을 화면에 채워 넣는 작업을 수행한다.
페인팅 과정은 일반적으로 여러 개의 레이어로 구성된 페인트 레이어 단위로 이루어진다. 브라우저는 효율적인 리페인트를 위해 요소들을 여러 레이어로 분리하고, 합성이라는 과정을 통해 이 레이어들을 최종적으로 화면에 표시한다. 특히 CSS 속성 중 transform이나 opacity를 사용하는 요소는 별도의 합성 레이어로 분리되어 처리되며, 이는 레이아웃이나 페인트 과정 없이 GPU를 이용한 빠른 애니메이션 처리를 가능하게 한다.
페인팅 성능은 요소의 시각적 복잡성에 직접적인 영향을 받는다. 박스 모델이 복잡하거나, 그라데이션과 블러 효과가 많거나, 폰트 종류가 많은 페이지는 페인팅에 더 많은 시간이 소요된다. 따라서 성능 최적화를 위해선 불필요한 CSS 스타일을 줄이고, 하드웨어 가속을 유도하는 속성을 사용하며, 너무 많은 DOM 노드를 생성하지 않는 것이 중요하다.
개발자는 크롬 DevTools의 Performance 패널이나 페인트 플래싱 도구를 이용해 페인팅이 발생하는 영역과 빈도를 분석할 수 있다. 화면의 일부만 업데이트할 때 전체 화면이 다시 그려지는 경우, 불필요한 리플로우와 리페인트를 유발하는 자바스크립트 또는 CSS 코드를 최적화함으로써 사용자 경험과 프레임률을 크게 향상시킬 수 있다.
3. 동작 과정
3. 동작 과정
크리티컬 렌더링 패스의 동작 과정은 브라우저가 네트워크로부터 HTML, CSS, JavaScript를 수신한 후, 이를 화면의 픽셀로 변환하기 위해 거치는 일련의 순차적 단계로 구성된다. 주요 목표는 사용자가 볼 수 있는 초기 렌더링을 가능한 한 빠르게 완료하는 것이다. 이 과정은 크게 다섯 가지 핵심 단계로 나뉘며, 각 단계는 이전 단계의 결과에 의존하여 진행된다.
먼저, 브라우저는 HTML 문서를 파싱하여 DOM 트리를 구축한다. 이 과정에서 파싱 차단 JavaScript를 만나면, DOM 생성이 일시 중단된다. 동시에, CSS 파일을 파싱하여 CSSOM 트리를 구축하는데, 이 CSSOM은 렌더링 차단 CSS로 작용하여 완성되기 전까지 렌더링을 지연시킨다. 이후, 완성된 DOM 트리와 CSSOM 트리를 결합하여 렌더 트리를 생성한다. 렌더 트리는 화면에 실제로 표시될 요소와 그 스타일 정보만을 포함한다.
다음 단계인 레이아웃에서는 각 요소의 정확한 위치와 크기를 계산한다. 이 과정은 때로 리플로우라고도 불리며, 뷰포트의 크기나 요소의 기하학적 속성 변경에 따라 다시 발생할 수 있다. 마지막으로 페인팅 단계에서 계산된 레이아웃 정보를 바탕으로 각 요소를 실제 픽셀로 채워 화면에 그린다. 이 페인팅 과정은 여러 레이어로 나누어 수행되기도 한다. 이 모든 단계를 최적화하여 중요 경로 길이와 중요 바이트를 줄이는 것이 웹 성능 개선의 핵심이다.
4. 최적화 기법
4. 최적화 기법
4.1. HTML 최적화
4.1. HTML 최적화
HTML 최적화는 크리티컬 렌더링 패스의 첫 단계인 DOM 트리 구축을 효율적으로 만들어 초기 렌더링 속도를 높이는 것을 목표로 한다. 핵심은 브라우저의 HTML 파서가 문서를 빠르게 해석하고 DOM 트리를 완성할 수 있도록 방해 요소를 최소화하는 것이다. 이를 위해 주로 파싱 차단 JavaScript의 영향을 줄이는 전략이 사용된다.
가장 기본적인 최적화는 스크립트 태그의 배치를 신경 쓰는 것이다. DOM 생성은 기본적으로 동기적으로 진행되며, 파서가 <script> 태그를 만나면 스크립트를 다운로드하고 실행할 때까지 HTML 파싱을 중단한다. 따라서 초기 렌더링에 불필요한 스크립트는 문서 하단에 배치하거나, async 또는 defer 속성을 사용하여 파싱 차단을 피하도록 한다. defer 스크립트는 파싱이 끝난 후 실행되어 DOMContentLoaded 이벤트 전에 실행 순서가 보장되는 반면, async 스크립트는 다운로드 완료 즉시 실행되어 순서가 보장되지 않는다.
시맨틱 HTML을 사용하고 불필요한 중첩 태그를 줄이는 것도 파싱 효율에 도움이 된다. 또한, CSS를 외부 파일로 분리하고 미디어 쿼리를 활용하여 특정 조건에서만 렌더링을 차단하도록 구성할 수 있다. 예를 들어, 프린트용 CSS 파일에는 media="print" 속성을 추가하면 초기 렌더링 경로에서 제외된다. 이미지 로딩 역시 loading="lazy" 속성을 사용하여 뷰포트 바깥의 이미지 로딩을 지연시켜 초기 중요 바이트를 줄일 수 있다.
4.2. CSS 최적화
4.2. CSS 최적화
CSS 최적화는 렌더링 차단 CSS를 최소화하여 CSSOM 트리 구축을 빠르게 완료하고, 렌더 트리 생성을 지연시키지 않도록 하는 것을 목표로 한다. 핵심은 브라우저가 첫 번째 페인트를 수행하는 데 필요한 최소한의 CSS만을 최우선으로 제공하는 것이다. 이를 위해 미디어 쿼리를 활용하여 모든 CSS 파일을 블로킹 리소스로 만드는 것을 피할 수 있다. 예를 들어, 화면 크기에 따라 적용되는 CSS를 분리하고, media 속성을 사용해 조건부로 로드하면, 초기 렌더링에 불필요한 CSS는 중요 경로에서 제외될 수 있다.
CSS 코드 자체의 효율성을 높이는 것도 중요하다. 과도하게 복잡한 선택자는 CSSOM 생성 시간을 늘릴 수 있다. 특히 자손 선택자나 복합 선택자보다는 클래스 선택자를 우선 사용하는 것이 일반적인 최적화 기법이다. 또한, CSS 파일 크기를 줄이기 위해 미니파이 도구를 사용하여 공백, 주석, 불필요한 코드를 제거하고, HTTP 압축을 활성화하여 전송되는 중요 바이트의 양을 감소시켜야 한다.
최적화 기법 | 주요 목적 | 예시/도구 |
|---|---|---|
미디어 쿼리 분리 | 렌더링 차단 범위 축소 |
|
CSS 미니파이 | 파일 크기 및 바이트 감소 | |
불필요한 CSS 제거 | CSSOM 트리 구축 시간 단축 | |
인라인 핵심 CSS | 첫 페인트를 위한 최소 CSS 즉시 제공 |
|
인라인 스타일을 전략적으로 사용하는 것도 방법이다. 첫 번째 화면을 렌더링하는 데 반드시 필요한 매우 작은 양의 CSS를 HTML 문서의 <head> 내에 인라인으로 포함시키면, 외부 CSS 파일에 대한 추가적인 네트워크 요청 없이 즉시 스타일을 적용할 수 있다. 이 기법은 중요 경로 길이를 줄이는 데 효과적이다. 나머지 CSS는 비동기적으로 로드하거나, 콘텐츠 전송 네트워크를 통해 빠르게 전송받도록 구성하여 전체적인 사용자 경험을 향상시킬 수 있다.
4.3. JavaScript 최적화
4.3. JavaScript 최적화
JavaScript 최적화는 크리티컬 렌더링 패스에서 파싱 차단 JavaScript의 영향을 최소화하여 초기 페이지 렌더링 속도를 높이는 것을 목표로 한다. 브라우저는 HTML 파서가 <script> 태그를 만나면 기본적으로 DOM 트리 구축을 중단하고 스크립트를 다운로드, 파싱, 실행한 후에야 파싱을 재개한다. 이로 인해 첫 화면이 표시되기까지의 시간이 지연될 수 있다. 따라서, 초기 렌더링에 반드시 필요하지 않은 스크립트는 비동기적으로 로드하거나 실행을 지연시켜야 한다.
주요 최적화 기법으로는 async와 defer 속성의 적절한 사용이 있다. async 속성이 지정된 스크립트는 다운로드가 완료되는 즉시 실행되며, DOM 파싱과 병렬로 다운로드된다. defer 속성이 지정된 스크립트는 다운로드는 병렬로 진행되지만, 실행은 전체 HTML 파싱이 완료된 후 DOMContentLoaded 이벤트 발생 전에 이루어진다. 초기 렌더링에 필수적인 스크립트는 인라인으로 포함시키거나, 중요하지 않은 스크립트는 defer를 사용하여 파싱 차단을 피하는 것이 일반적이다.
또한, JavaScript 코드 자체의 최적화도 중요하다. 불필요한 코드를 제거하는 트리 쉐이킹, 사용하지 않는 코드를 제거하는 데드 코드 제거, 코드를 압축하는 미니파이 기법을 적용하면 중요 바이트를 줄일 수 있다. 모듈 번들러를 활용하면 이러한 과정을 자동화하고 여러 스크립트 파일을 하나로 합쳐 HTTP 요청 수를 줄이는 효과도 얻을 수 있다. 코드 스플리팅을 통해 애플리케이션을 여러 번들로 나누고, 초기 로드 시 필요한 코드만 먼저 로드하는 방식으로 중요 경로 길이를 최적화할 수 있다.
5. 관련 도구
5. 관련 도구
크리티컬 렌더링 패스를 분석하고 최적화하는 데 도움이 되는 다양한 개발자 도구와 성능 측정 도구가 존재한다. 대표적인 도구로는 구글 크롬에 내장된 크롬 개발자 도구가 있으며, 여기서 Performance 패널을 사용하면 페이지 로드 과정을 상세히 기록하여 DOMContentLoaded 이벤트나 First Contentful Paint 같은 중요한 시점과 함께 각 렌더링 단계를 시각적으로 확인할 수 있다. 또한 Lighthouse는 웹 페이지의 성능, 접근성, 검색 엔진 최적화 등을 종합적으로 진단하고, 특히 First Meaningful Paint와 같은 사용자 중심의 성능 지표를 측정하여 크리티컬 렌더링 패스 최적화에 대한 구체적인 개선建議을 제공한다.
네트워크 조건을 시뮬레이션하고 리소스 로딩 우선순위를 분석하는 데에도 도구가 활용된다. 크롬 개발자 도구의 Network 패널은 각 리소스의 로드 타임라인을 보여주어 어떤 자원이 렌더링을 차단하는지 식별하게 해준다. WebPageTest 같은 온라인 도구는 다양한 지리적 위치와 브라우저 환경에서의 성능 측정이 가능하며, 필름스트립 보기 기능을 통해 시각적 진행 상황을 프레임별로 확인할 수 있어 렌더링 과정을 직관적으로 이해하는 데 유용하다.
명령줄 도구나 API를 통한 자동화된 분석도 가능하다. Lighthouse는 CI/CD 파이프라인에 통합할 수 있는 Node.js CLI 버전을 제공한다. PageSpeed Insights는 구글의 성능 측정 API를 기반으로 하여 URL을 입력하면 모바일과 데스크톱 환경에 대한 상세한 보고서를 생성한다. 이러한 도구들은 렌더링 차단 리소스를 식별하고, 이미지 최적화나 코드 압축과 같은 최적화 기법 적용 필요성을 판단하는 객관적인 기준을 마련해 준다.
