중요 렌더링 경로

중요 렌더링 경로 (Critical Rendering Path)는 브라우저가 HTML, CSS, Javascript를 화면에 픽셀로 전환되는 일련의 단계를 말하며 이를 최적화 하는 것은 렌더링 성능을 향상시킵니다. 중요 렌더링 경로는 Document Object Model (DOM), CSS Object Model (CSSOM), 렌더 트리 그리고 레이아웃을 포함합니다.

문서 객체 모델은 HTML을 파싱하여 생성됩니다. HTML은 Javascript를 요청할 수 있으며, 이 경우 DOM이 변경될 수 있습니다. HTML은 스타일을 포함하거나 요청하여, 결과적으로 CSS 객체 모델을 만듭니다. 브라우저 엔진은 이 두 가지를 결합하여 렌더 트리를 생성합니다. 레이아웃은 페이지에 있는 모든 요소에 관하여 크기와 위치를 결정합니다. 한 번 레이아웃이 결정되면 픽셀이 화면에 페인트 됩니다.

중요 렌더링 경로를 최적화 하는 것은 첫 번째 렌더링 시간을 개선합니다. 중요 렌더링 경로를 이해하고, 최적화 하는 것은 초당 60프레임이 유지되도록 리플로우와 리페인트를 보장하고 효율적인 사용자 상호작용을 보장하고 버벅거림을 피하는 데 중요합니다.

CRP 이해하기

웹 성능은 서버의 요청과 응답, 로딩, 스크립팅, 렌더링, 레이아웃 그리고 페인팅을 포함합니다.

웹 페이지 또는 어플리케이션에 대한 요청은 HTML 요청으로 시작됩니다. 서버는 HTML을 포함한 응답을 전달 받습니다. 그 다음 브라우저는 HTML 파싱을 시작하고 수신된 바이츠를 DOM 트리로 변환합니다. 브라우저는 스타일시트, 스크립트 또는 포함된 이미지 참조 같은 외부 자원 링크를 찾을 때마다 요청을 보냅니다. 불러온 자원을 처리할 때까지 HTML을 분석하는 작업 요청은 중단됩니다. 브라우저는 CSS 객체 모델을 구축하는 작업이 끝날 때까지 요청을 보내고 DOM을 생성하는 HTML을 계속해서 파싱합니다. DOM과 CSSOM이 완료되면 브라우저는 렌더 트리를 생성합니다. 그리고 보여지는 모든 콘텐츠의 스타일을 계산합니다. 렌더 트리가 완성된 후, 레이아웃이 시작되고 모든 렌더 트리 요소에 대한 위치와 크기가 정의됩니다. 레이아웃이 완료되면 페이지는 렌더 되거나 또는 화면에 '페인트'됩니다.

Document Object Model

DOM 구성은 점진적으로 증가합니다. HTML 응답은 토큰으로, 토큰은 노드로, 노드는 DOM 트리로 변환됩니다.1개의 DOM 노드는 시작태그 토큰으로 시작해서 끝태그 토큰으로 끝납니다. 노드는 HTML 요소와 관련있는 모든 정보를 가지고 있습니다. 그 정보는 토큰을 통해 설명됩니다. 노드는 토큰의 위계서열에 기반하여 DOM 트리 안에서 연결됩니다. 또 다른 시작태그와 끝태그의 묶음이 한 세트의 시작태그와 끝태그 사이에 있다면, DOM 트리의 위계서열을 정의하는 방법으로 노드 안에 노드가 있게 됩니다.

노드가 많아질수록 중요 렌더링 경로에서 이후로 이뤄지는 이벤트를 더 오래 발생시킬 것입니다. 측정해보세요! 얼마 되지 않는 노드 수는 큰 차이를 만들지 않지만 많은 노드를 추가하는 것은 성능에 영향을 줄 수 있는 것을 명심하세요.

CSS Object Model

DOM은 페이지의 모든 컨텐츠를 포함하고, CSSOM은 DOM을 스타일링 하기 위한 페이지의 모든 스타일 정보를 포함합니다. CSSOM은 DOM과 유사하지만 다릅니다. DOM의 구조는 점진적으로 증가하는 반면에 CSSOM은 그렇지 않습니다. CSS는 렌더링을 막습니다. 브라우저는 모든 CSS를 처리하고 수신할 때까지 페이지 렌더링을 막습니다. CSS는 규칙을 덮어 쓸 수 있기 때문에 렌더링을 막습니다. 그래서 CSSOM이 생성될 때까지 콘텐츠는 렌더링 될 수 없습니다.

CSS는 유효한 토큰을 식별하기 위해 스스로 규칙 세트를 가지고 있습니다. CSS의 C가 'Cascade'라는 의미를 기억해두세요. CSS 규칙은 아래로 종속됩니다. 분석기는 토큰을 노드로 변환해서, 하위 노드가 부모의 스타일을 상속 받습니다. 후속 규칙이 이전 규칙을 덮어쓸 수 있기 때문에, 점진적인 처리 기능이 HTML에서 적용되는 것처럼 CSS에서는 적용되지 않습니다. CSS 개체 모델은 CSS를 분석할 때 빌드됩니다. 하지만 CSS가 완전히 분석되기 전까지 렌더 트리로 빌드되지 않습니다. 추후 파싱되는 스타일과 덮혀 쓰여질 수 있어 화면에 렌더링되지 않아야 하기 때문입니다.

선택자 성능 측면에서, 덜 구체적인 선택자는 더 구체적인 선택자보다 빠릅니다. 예를 들어, 브라우저가 .foo 찾을때, .foo {}.bar .foo {} 보다 빠릅니다. 왜냐하면 두 번째 시나리오에서, .foo 가 부모 객체인 .bar 를 가지고 있는지 확인하기 위해 DOM을 거슬러 올라가기 때문입니다. 더 구체적인 태그는 브라우저에게 더 많은 작업을 요구하지만 이러한 패널티는 최적화 할 가치가 없습니다.

CSS 분석하는 소요 시간을 측정한다면, 브라우저가 정말 빠른 것에 놀랄 것입니다. 규칙이 구체적일수록 DOM 트리 안에서 더 많은 노드를 지나야 하기 때문에 더 많은 비용이 듭니다. 그러나 추가적인 비용은 일반적으로 최소입니다. 먼저 측정하세요. 필요할 때 최적화하세요. 특정 짓는 것은 아마도 가장 손쉬운 목표가 아닐 것입니다. CSS 측면에서, 선택자 성능 최적화와 개선은 오직 microsecond 밖에 되지 않될 것입니다. 축소화와 미디어 쿼리를 사용함으로써 지연된 CSS를 논-블로킹 요청으로 분리하는 것과 같은 CSS 최적화를 위한 다른 방법이 있습니다.

Render Tree

렌터 트리는 콘텐츠와 스타일 둘 다 캡쳐합니다. DOM과 CSSOM 트리는 렌더 트리에서 결합됩니다. 브라우저는 렌더 트리를 구성하기 위해 DOM 트리의 루트에서 시작해 모든 노드를 확인하면서 어떤 CSS 규칙을 첨부할지 결정합니다.

렌더 트리는 보이는 콘텐츠만 캡쳐합니다. 일반적으로 헤드 섹션은 보여지는 정보를 포함하고 있지 않으므로 렌더 트리 안에 포함되지 않습니다. 요소에 display: none 이 적용되어 있다면, 해당 요소 또는 하위 요소 또한 포함되지 않습니다.

Layout

한 번 렌더 트리가 생성되고 나면, 레이아웃이 실행됩니다. 레이아웃은 화면의 크기에 따라 결정됩니다. 레이아웃 단계는 요소가 페이지에서 배치되는 위치와 방법, 각 요소의 너비와 높이 그리고 서로 관련된 위치를 결정합니다.

요소의 너비는 무엇일까요? 정의에 따르면, 블럭 수준의 요소은 그 부모 너비의 기본 너비값의 100% 입니다. 50%의 너비를 갖는 요소는 부모 요소의 절반일 것입니다. 그렇게 정의되어 있지 않더라도, body 는 뷰포트 너비의 100%를 의미하는 너비 입니다. 디바이스의 너비는 레이아웃에 영향을 미칩니다.

뷰포트 메타 태그는 레이아웃에 영향을 주며 뷰포트 레이아웃의 너비를 정의합니다. 이 메타 태그가 없다면, 브라우저는 기본적인 뷰포트 너비를 사용합니다. 브라우저의 full screen 기본값은 일반적으로 960px 입니다. 기본적으로 브라우저의 full screen에서, 스마트폰의 브라우저와 같은 너비는 <meta name="Viewport" content="width=device-witdh"> 로 설정되어 있어 기본 뷰포트 너비 대신에 디바이스의 너비를 사용합니다. 디바이스 너비는 사용자가 디바이스를 가로 또는 세로로 돌릴 때마다 변경됩니다. 레이아웃은 디바이스를 회전하거나 브라우저 사이즈를 조정할 때마다 발생합니다.

레이아웃 성능은 DOM 영향을 받습니다. 노드 수가 많을수록 레이아웃은 더 오래 걸립니다. 스크롤링 또는 다른 애니메이션 중에 레이아웃이 필요하다면 버벅거림을 일으키는 병목현상이 발생할 수 있습니다. 로딩 또는 방향 전환에 20ms 정도 밀릴 수 있지만 애니메이션 또는 스크롤에 버벅거림을 유발할 수 있습니다. 노드 추가, 콘텐츠 변경이나 박스 모델 스타일을 업데이트 하는 경우 같이 렌더 트리가 수정되면 레이아웃이 발생합니다.

레이아웃 이벤트의 빈번도와 형성시간을 줄이기 위해서, 일괄적으로 업데이트 하고 박스 모델 속성을 애니메이션화 하지 마세요.

Paint

마지막 단계는 화면에 픽셀을 그리는 것입니다. 일단 렌더 트리가 생성되고 레이아웃이 시작되면, 픽셀은 화면에 페인트 됩니다. 로드 될 때, 전체 화면이 페인트 됩니다. 그 후에 브라우저는 필요한 최소 영역만을 다시 그리도록 최적화 되어 있기에, 영향 받은 영역만 화면에 다시 페인트 합니다. 페인트 시간은 렌더 트리에 적용되는 업데이트의 종류가 무엇인 지에 따라 달라집니다. 페인팅은 매우 빠르게 진행되는 과정으로 성능 향상에 가장 많은 영향력을 미치는 부분이 아닐 수 있습니다. 하지만 애니메이션 프레임 소요시간을 측정할 때, 레이아웃과 리페인트 시간을 모두 고려하는 것은 중요합니다. 각 노드에 적용된 스타일은 페인트 시간을 증가시키지만 페인트 시간을 0.001ms 증가시키는 스타일을 제거한다고 해서 최적화 효과가 큰 것은 아닙니다. 측정하는 것을 첫 번째로 기억하세요. 그러면 최적화 우선순위를 정해야 할지 말지 결정할 수 있습니다.

Optimizing for CRP

로드되는 자원의 우선순위 부여, 자원 로드 순서 관리, 파일 사이즈를 감소시켜 페이지 로드 속도를 개선하세요. 성능 개선 팁으로는 다음과 같이 있습니다. 1) 중요하지 않은 자원 다운로드를 미루거나 비동기로 적용하거나 제거하여 중요 자원 수 최소화 하기 , 2) 각 요청에 대한 파일 사이즈에 따라 필요한 요청 횟수 최적화 하기, 3) 다운 받을 중요 자원을 우선 시 하여 중요한 자원을 불러오는 순서를 최적화 하기, 그럼으로써 중요 경로 길이를 단축합니다.