CSS 로딩이 DOM 파싱과 렌더링에 미치는 영향

CSS 로딩이 DOM 파싱과 렌더링에 미치는 영향

웹 성능 최적화에서 CSS의 로딩, 파싱, 적용 과정은 매우 중요한 주제입니다.

 

이 과정을 이해하는 것은 페이지 로드 시간을 최적화하고 사용자 경험을 향상시키는 데 필수적입니다.

 

지금부터 CSS가 DOM의 파싱과 렌더링을 차단하는지, 그리고 그 메커니즘이 어떻게 작동하는지 자세히 알아보겠습니다.

1. CSS 로딩과 DOM 파싱

DOM 파싱이란?

DOM(Document Object Model) 파싱은 브라우저가 수신한 HTML 바이트 스트림을 DOM 트리로 변환하는 과정을 말합니다.

 

HTML 문서를 파싱하는 동안 브라우저가 비차단 리소스(예: 비동기 스크립트)를 만나면, 문서 파싱을 계속하면서 병렬로 해당 리소스를 다운로드하려고 시도합니다.

CSS는 DOM 파싱을 차단할까?

CSS 자체는 DOM 파싱을 차단하지 않습니다. 즉, 브라우저는 계속해서 HTML을 파싱하고 DOM 트리를 구성합니다.

 

하지만 CSS는 DOM 렌더링과 자바스크립트 실행을 차단합니다. 이는 DOM 트리가 구성될 수 있지만, 관련 CSS가 파싱될 때까지(즉, CSSOM 트리가 구축될 때까지) 브라우저가 렌더링 작업을 수행하지 않는다는 의미입니다.

 

이렇게 하는 이유는 페이지가 화면에 올바르게 표시되도록 하고, 리플로우와 리페인트 문제를 방지하기 위함입니다.

 

브라우저가 HTML을 파싱하여 DOM 트리를 생성할 때, 병렬로 CSS 파일을 다운로드하고 CSSOM(CSS Object Model)을 구성하기 시작합니다.

 

DOM과 CSSOM의 구성은 동시에 이루어지므로, CSS 다운로드 및 파싱은 DOM 구축을 차단하지 않습니다.

2. CSSOM 트리와 렌더링

CSSOM 트리

CSSOM(CSS Object Model)은 DOM과 병렬로 존재하는 데이터 구조로, 페이지의 모든 CSS 정보를 포함합니다.

 

브라우저는 이를 사용하여 렌더링 트리를 구성합니다.

 

브라우저가 <link> 태그나 <style> 태그를 만나면, 렌더링을 일시 중지하고 CSS 로딩과 파싱을 우선시하며 CSSOM 트리를 구축합니다.

렌더링 트리 구성

렌더링 트리는 DOM 트리와 CSSOM 트리를 결합한 결과물로, 브라우저가 렌더링할 내용을 나타냅니다.

 

렌더링 트리는 CSSOM 트리가 완성될 때까지 구성될 수 없습니다. 왜냐하면 렌더링 트리는 모든 DOM 요소에 대한 스타일 정보를 필요로 하기 때문입니다.

3. CSS 로딩이 자바스크립트를 차단하는 이유

정확한 스타일 계산 보장

CSS가 완전히 로드되고 파싱되기 전에 자바스크립트가 DOM을 수정하거나 스타일을 계산하려고 하면, 자바스크립트가 검색하는 스타일 정보가 부정확할 수 있습니다.

 

이를 방지하기 위해 브라우저는 자바스크립트를 실행하기 전에 모든 관련 CSS가 로드되고 파싱되도록 합니다.

 

그래야 스크립트가 DOM 요소에 대한 최종 스타일을 검색할 수 있습니다.

리플로우와 리페인트 방지

CSSOM이 불완전한 상태에서 자바스크립트가 실행되도록 허용하면, 불완전한 스타일 정보를 기반으로 DOM을 수정할 수 있습니다.

 

CSSOM이 구성되면 브라우저는 이미 렌더링된 요소를 리플로우하고 리페인트해야 할 수 있으며, 이는 렌더링 효율성을 크게 떨어뜨립니다.

파싱 순서에 대한 의존성

HTML 파싱 중 브라우저가 <link rel="stylesheet" href="..."> 태그를 만나면 즉시 CSS 로딩을 시작합니다.

<script> 태그(async 또는 defer 속성 없음)를 만나면 스크립트를 실행하기 위해 DOM 파싱을 일시 중지합니다.

 

CSS가 완전히 로드되지 않았다면 스크립트 실행이 불완전한 스타일 정보에 의존할 수 있습니다.

 

따라서 브라우저는 스크립트를 실행하기 전에 CSSOM이 준비될 때까지 기다립니다.

4. 자바스크립트에서 CSS 작성이 DOM 렌더링을 차단할까?

자바스크립트에서 CSS 스타일을 작성하는 것이 DOM 렌더링을 차단하는지는 스타일이 어떻게, 언제 적용되는지에 따라 달라집니다.

 

이는 브라우저의 렌더링 프로세스, 특히 자바스크립트, CSS, DOM 간의 관계와 관련이 있습니다.

요소 스타일 직접 수정

자바스크립트에서 DOM 요소의 style 속성을 직접 수정하여 CSS 스타일을 적용할 때(예: element.style.color = 'red';), 이러한 작업은 일반적으로 DOM 파싱을 차단하지 않습니다.

 

하지만 브라우저가 스타일을 재계산하고 리플로우와 리페인트를 트리거할 수 있기 때문에 렌더링 프로세스를 차단할 수 있습니다:

  • 리플로우: 요소의 크기, 구조 또는 특정 속성이 변경될 때 발생하며, 브라우저가 요소의 위치와 크기를 재계산해야 합니다.
  • 리페인트: 요소의 시각적 모양이 변경될 때(예: 색상이나 테두리) 크기나 구조에 영향을 주지 않고 발생하며, 브라우저가 요소를 다시 그려야 합니다.

<style> 또는 <link> 태그 동적 삽입

자바스크립트가 <head><style> 또는 <link> 태그를 동적으로 추가하면 렌더링에 영향을 미칠 수 있습니다:

  • 렌더링 차단: 브라우저는 렌더링을 계속하기 전에 새로 삽입된 CSS 규칙을 파싱하기 위해 일시 중지해야 합니다. 특히 CSS 파일이 크거나 네트워크 상태가 좋지 않은 경우 상당한 렌더링 지연을 일으킬 수 있습니다.
  • 성능 영향: 루프에서 <style> 태그를 삽입하는 것과 같은 반복적인 작업은 반복적인 리플로우와 리페인트를 일으켜 페이지 성능에 심각한 영향을 미칠 수 있습니다.

자바스크립트에서 CSS를 부적절하게 처리하면, 특히 스타일이 동적으로 생성되고 적용될 때 DOM 렌더링을 차단하거나 지연시킬 수 있습니다.

결론

CSS 로딩은 DOM 파싱을 차단하지 않지만, DOM 렌더링은 차단합니다.

 

또한 CSS 로딩은 이후의 자바스크립트 실행도 차단합니다.

 

이러한 메커니즘을 이해하면 웹 페이지의 성능을 최적화하는 데 큰 도움이 됩니다.