Critical Render Path란 무엇인가


  • Critical Render Path에 대해서 공부하고 정리한 내용입니다.

Criticala Rendering Path

  • html 페이지에서 브라우저가 표시할 수 있는 이 단계까지를 Critical Rendering Path라고 한다

  • 브라우저가 URL을 입력하게 되면 다음과 같은 순서로 진행된다

  • Request / Response -> Loaindg -> Scripting -> Rendering -> Layout -> Painting

  1. Request / Response

    • 브라우저가 서버에게 html 파일 요청
  2. Loading

    • html 파일을 서버에서 데이터 받아서 로딩
  3. Scripting

    • html 파일을 한 줄씩 읽어서 DOM요소로 변환
    • CSS요소를 CSSOM으로 변환
  4. rendering

    • 브라우저에 표시하기 위해 Render Tree만든다
  5. layout

    • 렌더링 트리를 만든 다음에 어떤 위치에 얼마나 그릴지 계산해준다
  6. painintg

    • 앞서 계산한 것들을 브라우저에 그려준다

  • 앞의 과정을 어떤 일을 하는지에 따라 카테고리를 나눠서 생각해보면 다음과 같이 Construction PartOperation Part로 나눌 수 있다

Construction Part

  • DOM → CSSOM → Render Tree

  • Construction Part는 Render Tree 까지 만드는 과정을 포함한다

  • Construction Part는 앞의 순서에서 Request / Response -> Loaindg -> Scripting -> Rendering 단계 까지를 포함한다

Operation Part

  • Layout → Paint → Composition

  • Render Tree 를 이용해서 구조를 작성하고 어디에다 배치할 건지 계산을 한 다음에 실제로 브라우저 window에 그림을 그려주는 부분이 operation Part이다.

  • Operation Part는 앞의 순서에서 Layout -> Painting 까지를 포함한다


Layout

  • Render Tree에는 DOM 요소 뿐 아니라 최종적으로 계산된 CSS 스타일이 포함되어져 있다

  • 따라서 이 정보 기반으로 요소의 크기와 어느 위치에 배치 계산하여 레이아웃을 구성한다.

  • 이 요소는 이 정도 위치에, 그리고 이 정도 크기에 배치하고, 다른 요소는 또 다른 곳에 두겠다고 레이아웃을 구상하는 단계이다

  • x와 y 그리고 width와 height 같은 것들이 계산된다

Paint

  • Layout 다음으로 Paint 과정이 일어난다

  • 앞서 Layout 과정에서 계산한 요소들을 브라우저에 바로 그리는 것이 아니라 이 요소들을 어떻게 배치했느냐에 따라 Paint 과정에서는 각각 잘게 나누어서 이미지를 준비해 놓는다.

  • 이러한 각각의 요소들, 이미지를 비트맵이라고 한다.

  • 즉, Paint 과정에서 컴퓨터가 이해할 수 있는 비트맵 데이터로 변환된다

  • 브라우저에 따라 다양한 속성 값에 따라 layer를 만들게 된다

  • z-index를 사용한다고해서 무조건 layer가 만들어지는 것은 아니지만 간단한 예로, css에 z-index가 적용되어 다른 부분 보다 높은 z축의 순서를 가지는 부분이 있으면 브라우저는 이를 따로 묶어서 Layer를 준비하고 또 나머지 z-index가 같은 부분이 있으면 이를 묶어서 Layer로 준비하는 방식으로 Paint 단계에서는 Layer 기능을 이용해서 각 Layer 별로 준비해 놓는다

  • 이렇게 하는 이유 브라우저가 성능개선을 위해 스스로 준비하는 것이다

  • 만약 앞서 Layout 단계에서 계산한 요소의 위치를 움직이거나 투명도를 바꾸는 경우 Layer 기능을 이용하지 않는다면 브라우저는 한 부분만 바꾸기 위해 전체적으로 다시 그림을 그리고 업데이트 된 부분을 변경해주어야 한다

  • 하지만 레이어를 사용하면 특정 레이어가 변경되었을 때 그 레이어만 변경시키면 된다

  • 예를 들어, CSS에는 will-change 속성이 있는데 이 속성을 요소에 적용하게 되면 브라우저는 해당 요소가 나중에 변할 수도 있다는 것을 알게되고 해당 요소를 위한 새로운 Layer를 준비한다

  • 따라서 will-change속성이 적용된 요소가 opacity 가 바뀐다면 해당 layer만 다시 바뀌게 되는 것이다

  • 하지만 will-change 속성을 너무 많이 쓰면 불필요하게 너무 많은 레이어를 준비하게 되서 브라우저 성능이 안좋아질 수 있기 때문에 남용해서 사용하는 것은 좋지 않다

  • 레이어는 가급적이면 작을 수록 성능향샹에 좋다

  • 브라우저마다 어떻게 레이어를 형성하는지는 내부 구현 방식에 따라서 달라 지겠지만 대부분은 transform이나 opacity 그리고 will-change 같은 요소들을 쓰면 새로운 레이어가 만들어진다

Composition

  • Composition 단계에서는 앞의 Layout과 Paint 단계를 거쳐 준비된 Layer들을 순서대로 차곡차곡 브라우저 위에 표시한다

  • z-index 순서로 낮은 순서부터 시작해서 z-index가 가장 높은 layer를 제일 나중에 브라우저에 표시한다


  • Construction Part에서 주의할 점

    • Construction Part는 DOM요소로 변환하고 CSSOM을 만들고 이를 합쳐서 Render Tree 까지 만드는 것을 의미하고 그 다음에 Operation Part에서 Layout, Paint, Composition을 통해서 최종적으로 사용자에게 웹 페이지가 보여지게 되는 것이다

    • DOM에서 렌더링 트리를 빠르게 만들 수 있는 방법은 DOM 요소가 작으면 작을 수록 그리고 CSS 규칙이 작으면 작을 수록 트리가 작아지기 때문에 빠르게 만들 수 있다

    • 따라서 불필요한 태그, 예를 들면 div 또는 wrapping 클래스나 wrapping 요소를 만드는 것 이러한 것들 자제해서 최대한 요소들을 작게 만드는 것이 중요하다

  • Operation Part에서 주의할 점

    • 처음에 사용자에게 화면을 보여주는 것더 중요하지만 나중에 사용자가 클릭을 해서 요소를 움직이거나 애니메이션을 사용할 때 Paint가 자주 일어나지 않도록 만드는 것이 중요하다

    • 만약 페이지에 네모 박스가 있는데, 네모 박스를 transform 속성을 사용해서 움직이기만 하면 Layer가 이미 준비되어 있고 Layer의 위치만 이동하면 되기 때문에 paint는 일어나지 않고 composition만 일어나게 된다

    • 이러한 경우에는 Layer의 위치만 바꾸면 되기 때문에 성능이 괜찮게 작동할 수 있지만 다시 Layer가 만들어져야 하는 경우에는 Paint가 다시 발생하기 때문에 좋지 않다.

    • 가장 최악의 경우는 Layout이 다시 발생하는 경우이다

    • 만약 앞의 예시에서 네모 박스가 움직임으로 인해서 다른 주변에 있는 요소들의 position이 바뀌어야 한다면, 브라우저는 다시 Layout 부터 시작해서 요소의 위치를 계산한 다음 Paint, Composition이 이루어지기 때문에 성능이 나빠질 수 밖에 없다

    • 자바스크릡트나 CSS로 DOM 요소를 조작할 때 composition 만 일어나면 best 인 경우이고, paint는 나쁘지 않지만 좋지도 않은 경우, layout 다시 일어나는 것은 worst인 경우이다

    • 따라서 애니메이션 사용할 때 layout이 다시 일어나면 이 애니메이션이 필수적일까 다시 한번 생각해 보고 속성을 지정한다


  • 다음은 will-change 속성을 사용했을 때 새로운 Layer가 만들어지는 것을 확인할 수 있는 예시이다

  • Chrome 개발자 도구의 More tools-Layers 에서 Layer를 확인할 수 있다

  • 다음과 같이 코드가 작성된 경우 Rotete mode에서 Layer를 확인해 보면 innerbox의 z-index는 100이지만 두 요소가 한번에 표기 되기 때문에 같은 Layer인 것을 확인할 수 있다

<!-- html -->
<body>
  <div class="box">
    <div class="innerbox"></div>
  </div>
</body>
/* css */
.box {
  width: 500px;
  height: 500px;
  background-color: blueviolet;
}

.innerbox {
  width: 100px;
  height: 100px;
  background-color: cornflowerblue;
  z-index: 100;
}
  • 하지만 다음과 같이 will-change 속성을 사용해서 이 요소의 opacity가 바뀔 수 있다는 것을 지정해주고 다시 Layer를 확인해보면 별도의 layer가 만들어 진 것을 확인할 수 있다

  • 만약 두 요소가 한 layer에 있는 경우에는 innerbox의 opacity가 변경될 때 마다 브라우저는 한 layer 전체를 업데이트 하게 된다.

  • 하지만 will-change 속성을 사용해서 opacity가 바뀔 수 있다는 것을 지정해주면 새로운 layer가 만들어지게 되고 innerbox의 opacity가 변경 될 때 해당 layer만 변경되는 것이다

<!-- html -->
<body>
  <div class="box">
    <div class="innerbox"></div>
  </div>
</body>
/* css */
.box {
  width: 500px;
  height: 500px;
  background-color: blueviolet;
}

.innerbox {
  width: 100px;
  height: 100px;
  background-color: cornflowerblue;
  z-index: 100;
  will-change: opacity;
}

  • CSS Triggers 참고해서 내가 사용하는 CSS의 속성값에 대해 확인할 수 있다

  • 아래 그림에서 Blink엔진은 크롬 브라우저, Gecko는 파이어폭스, Webkit은 iOS 사파리, EdgeHTML은 구형 엣지 브라우저에서 사용되는 엔진이다

  • Change from default은 처음에 css 기본 값에서 어떠한 단계가 일어나는지를 보여주고 Subsequent updates는 주기적으로 업데이트 될 때, 예를 들어 한번 렌더링이 발생하고 나서 애니메이션이 되는 경우 발생할 수 있는 절차를 보여준다

  • CSS를 쓸 때는 괜찮지만 나중에 animation이나 transition을 이용할 때 어떤 속성값, 어떤 CSS를 사용하느냐에 따라 layout이 발생할 수도, paint가 발생 할 수도 아니면 가장 좋은 case인 compositoin이 발생할 수도 있다

  • CSS가 변경되었을 때 Composition만 일어나면 기존의 이미 그려져 있는 layer를 움직이거나 변형만 하면 되니까 가장 좋은 case이다

  • 하지만 paint가 일어나게 되면 다시 layer를 준비해야 하기 때문에 시간이 걸리고 메모리에 부담이 될 수 있다

  • 최악의 경우는 Layout으로 처음부터 Render Tree를 계산하고, 그 다음 X와, Y 그리고 Width와 Height를 계산한 다음에 Paint, Composition 단계를 거쳐야 하기 때문이다

  • 아래의 opacity 속성을 보면 처음에는 Blink엔진을 사용하는 경우에는 layout이 발생하지 않고 paint와 composition만 일어나는 것을 볼 수 있다

  • 그리고 추가적으로 업데이트 되는 경우에는 paint가 이렁나 composition만 일어나는 것을 확인할 수 있다

  • 하지만 Webkit, EdgeHTML 엔진에서는 Layout, Paint, Composition 모든 단계가 일어난 것을 볼 수 있다

  • width을 확인해보면 요소의 너비가 변경되었기 때문에 모든 엔진에서 Layout이 발생하는 것을 확인할 수 있다

  • 또한 top과 left 같은 속성을 확인해보면 Layout, Paint, Composition 모든 단계가 일어나기 때문에 Paint 단계만 일어나는 transform 속성을 사용해서 요소를 움직이는 것이 좋다


Reference









© 2020. by dkmqflx

Powered by dkmqflx