브라우저가 서버에서 페이지의 HTML에 대한 응답을 받으면 화면에 표시되기 전에 많은 단계를 거쳐야 한다. 브라우저가 서버에서 응답을 받아 하나의 화면을 그려내는 순서를 Critical Rendering Path(CRP)라고 한다. 사이트의 성능을 향상 시키는 방법을 이해하는 데에 있어 CRP 에 대한 지식은 매우 유용하다.
CRP 는 다음과 같은 6단계로 구성된다.
- DOM 트리 구축
- CSSOM 트리 구축
- Javascript 실행
- 렌더링 트리 구축
- 레이아웃 생성
- 페인팅
CRP 를 최적화하는 작업은 위 단계들을 수행할 때 걸리는 총 시간을 최소화하는 프로세스 이다.
현재 사용자 작업과 관련된 콘텐츠 표시의 우선순위를 지정하는 것을 말한다.
브라우저가 페이지를 렌더링 하려면 먼저 DOM 및 CSSOM 트리를 생성해야 한다. 따라서 HTML 및 CSS 를 가능한 빨리 브라우저에 제공해야 한다.
- HTML 마크업은 DOM 으로 변환되고, CSS 마크업은 CSSOM 으로 변환된다.
- DOM 및 CSSOM 은 서로 독립적인 데이터 구조이다.
DOM 트리는 완전히 구문 분석된 HTML 페이지의 Object 표현이다. 루트요소인 <html>
로 시작하여 페이지의 각 element/text 에 대한 노드가
만들어 진다.
HTML 마크업이 여러 태그 간의 관계를 정의하기 때문에 생성된 객체는 트리 데이터 구조 내에 연결된다.
이 트리 데이터 구조 안에는 원래 마크업에 정의된 상위-하위 관계도 포함된다.
HTML 의 장점은 부분적으로 실행 될 수 있다는 점이다. 페이지에 내용을 표시하기 위해 전체 문서를 로드할 필요가 없다. 그러나, CSS 와 javscript 는 페이지 렌더링을 차단할 수 있다.
브라우저는 단순한 페이지의 DOM 을 생성하는 동안 외부 CSS 스타일시트인 style.css
를 참조하는 문서의 헤드 섹션에서 링크 태크를 접한다.
페이지를 렌더링 하는 데 이 리소스가 필요할 것이라고 판단한 브라우저가 이 리소스에 대한 요청을 즉시 발송하고 요청의 결과로 다음 콘텐츠가 반환된다.
body {
font-size: 16px;
}
p {
font-weight: bold;
}
img {
float: right;
}
HTML 마크업 내에 직접 스타일을 선언할 수도 있지만 CSS 와 HTML 을 별도로 유지하면 콘텐츠와 디자인을 별도의 항목으로 처리할 수 있다.
HTML 과 마찬가지로 수신된 CSS 규칙을 브라우저가 이해하고 처리할 수 있는 형식으로 변환해야 한다.
따라서 HTML 대신 CSS 에 대해 HTML 프로세스를 반복한다.
CSS는 "렌더링 차단 리소스" 로 간주된다. 즉, 먼저 리소스를 완전히 파싱하지 않으면 렌더링 트리를 구성할 수 없다.
HTML 과 달리 CSS 는 계단식 상속 특성 때문에 부분적으로 실행될 수 없다.
문서의 뒷부분에 정의된 스타일은 이전에 정의된 스타일을 무시하고 변경할 수 있다. 즉 다음 단계로 넘어가기 전에 CSS 를 완전히 파싱해야 한다. CSS 는 "script blocking" 일 수도 있다. javscript 파일이 실행되기 전에 CSSOM 이 생성될 때까지 기다려야 하기 때문이다.
CSSOM 이 트리구조를 가지는 이유가 뭘까? 페이지에 있는 객체의 최종 스타일을 계산할 때 브라우저는 해당 노드에 적용 가능한 가장 일반적인 규칙(예: body 요소의 하위인 경우 모든 body 스타일 적용)으로 시작한 후 더욱 구체적인 규칙을 적용하는 방식, 즉 하향식으로 규칙을 적용하는 방식으로 계산된 스타일을 재귀적으로 세분화한다.
자바스크립트를 사용하면 콘텐츠, 스타일 지정, 사용자 상호작용에 대한 응답 등 페이지의 서의 모든 측면을 수정할 수 있다.
하지만 자바스크립트는 DOM 생성을 차단하고 페이지가 렌더링될 때 지연시킬 수도 있다. javascript 는 "파서 차단 리소스" 로 간주된다.
즉 HTML 문서 자체의 구문 분석은 javascript 에 의해 차단된다.
최적의 성능을 제공하려면 자바스크립트를 비동기로 설정하고 주요 렌더링 경로에서 불필요한 자바스크립트를 제거하는 것이 좋다.
- 자바스크립트는 DOM 및 CSSOM 을 수정할 수 있다.
- 자바스크립트의 실행은 CSSOM 을 차단한다.
- 자바스크립트는 명시적으로 비동기로 선언되지 않은 경우 DOM 생성을 차단한다.
자바스크립트는 기존 DOM 노드의 콘텐츠와 CSS 스타일을 수정하고 완전히 새로운 노드를 문서에 추가할 수 있다. 그러나 자바스크립트는
페이지의 렌더링 방식과 시기에 있어 많은 제한이 있다. 스크립트는 문서에 삽입된 정확한 지점에서 실행된다.
즉 인라인 스크립트를 실행하면 DOM 생성이 차단되고, 이로 인해 초기 렌더링도 지연되게 된다.
- 문서에서 스크립트의 위치는 중요하다.
- 브라우저가 스크립트 태그를 만나면 이 스크립트가 실행 종료 될 때까지 DOM 생성이 일시 중지된다.
- 자바스크립트의 실행은 CSSOM 이 준비될 때 까지 일시중지 된다.
HTML5 에서는 script 태그에 비동기 속성을 추가하여 파서가 차단되는 것을 피할 수 있다.
<script async src="script.js">
일반적으로 '주요 렌더링 경로 최적화'란 HTML, CSS 및 자바스크립트 간의 종속성 그래프를 이해하고 최적화하는 것을 말합니다.
CSSOM 및 DOM 트리는 결합하여 렌더링 트리를 형성한다. DOM 은 콘텐츠를 설명하고, CSSOM 은 문서에 적용되어야 하는 스타일 규칙을 설명한다.
- DOM 과 CSSOM 트리는 결합되어 렌더링 트리를 형성한다.
- 렌더링 트리에는 페이지를 렌더링 하는 데 필요한 노드만 포함된다.
브라우저가 렌더링 트리를 생성하기 위해 수행하는 작업은 다음과 같다.
- DOM 트리의 루트에서 시작하여 표시되는 노드 각각을 순회한다.
일부 노드는 표시되지 않으며(ex. 스크립트 태그, 메타 태그 등), 렌더링 된 출력에 반영되지 않으므로 생락한다. 또한 CSS 를 통해 숨겨져 렌더링 트리에서 생략될 수도 있다.
- 표시된 각 노드에 대해 적절하게 일치하는 CSSOM 규칙을 찾아 적용한다.
- 표시된 노드를 콘텐츠 및 계산된 스타일과 함께 내보낸다.
렌더링 트리가 생성되면 '레이아웃' 단계로 진행할 수 있다.
이전 단계까지 표시할 노드와 스타일을 계산했다. 그러나 기기의 뷰포트 내에서 노드의 정확한 위치와 크기는 계산되지 않았다. 이 것이 바로 '레이아웃' 단계이며, 경우에 따라 '리플로우' 라고도 한다.
- 레이아웃은 각 객체의 정확한 위치와 크기를 계산한다.
레이아웃 프로세스에서는 뷰포트 내에서 각 요소의 적황한 위치와 크기를 정확하게 캡처하는 '박스 모델'이 출력된다. 모든 상대적인 측정값은 화면에서 절대적인 픽셀로 변환된다.
- 첫번째 DOM 생성시
- HTML chunk 가 발생할 때 (by script)
- Html element 크기나 위치가 변경될 때
- Sub-resources 가 로드 될때 (e.g. image)
렌더링 트리의 각 노드를 화면의 실제 픽셀로 변환하는 마지막 단계로 이 단계를 '페인팅' 또는 '래스터화' 라고 한다.
- 마지막 단계는 최종 렌더링 트리에서 수행되는 페인트이며, 픽셀을 화면에 렌더링한다.