Reflow와 Repaint에 대해서 너무 겉핥기로만 알고있는게 아닐까.. 고민하게 만들어준 문제입니다.

단순히 어떤 동작이 발생하는지만 파악하고 넘어가는 것보다는 사용하는 CSS 속성에 따라 어떻게 렌더링 과정이 달라지는지, 또는 어떻게 하면 CSS 속성을 바꿔서 렌더링 최적화를 할 수 있을 지에 대해서 알아보는 것도 좋지 않을까요?

그런 의미에서 오늘은 CSS의 transform속성을 이용한 최적화에 대해서 알아보려고 합니다.

(많은 자료들을 통해 최대한 검증하려고 노력하였으나, 그럼에도 틀린 부분이 있다면 언제든지 가차없이 댓글을 남겨주시면 감사드리겠습니다!)

 

목차


    0. 렌더링 엔진

    각각의 브라우저는 렌더링에 사용되는 렌더링 엔진을 가지고 있습니다.

    이 렌더링 엔진은 표준이 따로 없기 때문에 브라우저마다 각각 다른 렌더링 엔진을 사용하기도 하는데요!
    크롬과 엣지, 네이버 웨일로 대표되는 크로미움 기반 브라우저는 Blink, 파이어폭스는 Gecko, 사파리는 Webkit을 사용합니다.
    추가로 EdgeHTML이라는 렌더링 엔진이 가끔 보이는데, 이것은 크로미움 기반의 엣지 브라우저 이전의 레거시 엣지 브라우저에서 사용하는 렌더링 엔진입니다. (거의 안보이겠지만, Trident는 이미 그 수명을 다한 IE에 사용되던 렌더링 엔진입니다.)

    이 렌더링 엔진이 바로 브라우저에서 그래픽 형태로 요소를 출력할 때 일을 하게 되는 것이죠!!

    이렇게 각각의 브라우저가 다른 렌더링 엔진을 사용하기 때문에 개발자들은 각각의 렌더링 엔진에 대해서 따로 테스트를 진행해서 호환성 검사를 하게 됩니다. (갈려나가는 개발자 ㅠㅠ)


    아무튼!! 이러한 렌더링 엔진은 서로 다른 프로세스를 통해서 렌더링을 진행하지만, 전체적으로는 아래와 같은 프로세스를 통해 우리의 화면에 요소들을 보여주게 됩니다.

    이렇게 브라우저가 페이지의 초기 출력을 위해 실행해야 하는 순서를 Critical Rendering Path(CRP)라고 부르기도 합니다!

    Blink의 렌더러 프로세스 / 출처 : https://docs.google.com/document/d/1aitSOucL0VHZa9Z2vbRJSyAIsAz24kX8LFByQ5xQnUg/edit#

     

    Life of a Pixel / 출처 : https://docs.google.com/presentation/d/1boPxbgNrTU0ddsc144rcXayGA_WF53k96imRH8Mp34Y/edit#slide=id.ga884fe665f_64_1800

     


    1. 간단히 복습하는 렌더링 프로세스

    1.0. DOM / CSSOM

    먼저 어떠한 데이터를 서버에 요청을 하게 되면 서버로부터 HTML과 CSS를 받게 됩니다.
    서버로부터 받은 HTML과 CSS는 단순한 텍스트 형태이므로, 이걸 관리하기 위해서 데이터를 파싱하여 Object Model형태로 만들어주게 됩니다.

    HTML을 DOM으로 만든 후에 CSS를 CSSOM으로 만들게 되는데, CSSOM으로 구조화하는 과정에서 DOM요소들에 대한 CSS 스타일 정보가 포함됩니다.
    그리고 CSSOM에는 <meta>, <script>, <title>과 같은 화면과 관련 없는 DOM 요소들은 제외됩니다.

    TMI를 하나 풀자면, CSS 속성은 따로 정의되어 있지 않더라도 W3C CSS 기준에 따라 정의된 속성이 default로 적용됩니다.
    또한 상속 자격이 있는 속성들 역시 상속 규칙이 적용됩니다.
    예를 들면 font-size와 같은 스타일은 HTML요소에서 누락되면 부모의 값을 상속받습니다.
    이 말은 HTML 요소와 모든 하위 요소에 해당 속성이 있다는 것과 같습니다. 이게 바로 Cascading of style이고, CSS(Cascading Style Sheet)라는 이름은 여기서 나오게 되었답니다!!

    아무튼..!! HTML파일을 DOM으로 만들고, CSS를 이용해서 CSSOM을 만드는 과정은 아래 문서에 보다 자세하게 설명되어 있으니 참고하세요!!

     

    Constructing the Object Model

    Learn how the browser constructs the DOM and CSSOM trees.

    web.dev

     

    1.1. Render Tree

    DOM과 CSSOM이 모두 생성되었다면 이것들을 이용해서 Render Tree를 생성합니다.
    Render Tree는 실제로 화면에 표시되는 요소들만 추려서 트리 형태로 만들어줍니다.
    DOM에 담겨있는 문서의 내용과 CSSOM에 담겨있는 스타일 규칙들을 실제로 적용하는 단계입니다.
    브라우저는 이 렌더트리를 사용해서 보이는 요소들에 대한 위치정보를 계산하고 화면에 그려주는 것이죠.

    적용 이외에도 조금 더 특이한 점이라고 한다면, 픽셀 영역을 차지하지 않는 요소은 포함하지 않습니다.

    대표적인 예시가 바로 display: none 입니다. CSS에서 display: none 속성을 통해서 숨겨지는 영역은 Render Tree에도 포함되지 않습니다. (visibility: hidden, opacity: 0 으로 숨겨지는 요소는 레이아웃에서 여전히 공간을 차지하고 있다는 점을 기억해두어야 합니다!)

    출처 :&amp;amp;nbsp;https://web.dev/critical-rendering-path-render-tree-construction/

     

    1.2. Layout

    Render Tree에 정의된 화면에 표시할 노드들과 스타일들을 실제로 배치하는 단계입니다.
    Render Tree를 루트에서부터 탐색하여 요소들이 정확한 크기를 가지고, 정확한 위치에 들어갈 수 있도록 계산합니다. (이 과정에서 발생하는 상대측정값은 전부 절대 픽셀로 변환됩니다!)

    아래 예시에서는 전체 영역에 대비하여 각각 div들이 50%의 width를 가졌을 때 어떻게 layout이 이루어지는지에 대해 나와있습니다.

    출처 :&amp;amp;nbsp;https://web.dev/critical-rendering-path-render-tree-construction/

     

    1.3 Paint

    이제 위에서 계산한 내용과 해당 요소의 style 및 geometry 정보를 모두 결합하여 실제 화면을 그릴 준비를 마치는 단계입니다.
    간단하게 말해서 위치와 크기 정보를 제외한 나머지 CSS 속성(color, background-color, border, outline, visibility 등등)들을 각각의 DOM 요소에 적용하는 것이죠!

    1.4 Composite

    Blink의 렌더러 프로세스에서 맨 마지막 줄에 위치한 compositor thread 부분이 바로 해당 단계입니다.
    열심히 준비한 내용을 합성해서 실제로 Browser에 노드를 그리는 단계이죠.
    이 과정에서는 갑자기 GPU가 끼어들어서 열일을 하게 됩니다.

    (앞으로 더 설명하겠지만, 이 친구가 바로 오늘의 주인공입니다! ㅋㅋㅋ)

    다시 보는 Life of a Pixel / 출처 : https://docs.google.com/presentation/d/1boPxbgNrTU0ddsc144rcXayGA_WF53k96imRH8Mp34Y/edit#slide=id.ga884fe665f_64_1800

     


    2. Reflow, Repaint, Composite

    2.0. Reflow와 Repaint

    렌더링 최적화를 이해하고 적용하기 위해서는 위 내용에 더해서 Reflow와 Repaint에 대한 내용을 알아야 합니다.
    Reflow와 Repaint는 말 그대로 layout과 paint 과정을 다시 하는 것입니다.

    실제로 화면에 요소를 그리는 픽셀 파이프라인 과정을 살펴보면서 더 자세하게 알아봅시다!

    특정한 액션에 의해서 요소의 크기나 위치와 같은 레이아웃이 변경되는 경우 Reflow가 발생합니다.
    요소의 크기가 아닌 창의 크기를 변경하는 경우(뷰포트의 크기가 변경되는 경우), 폰트가 바뀌는 경우에도 Reflow가 발생합니다.

    출처 :&amp;amp;nbsp;https://web.dev/rendering-performance/


    RepaintReflow 과정이 일어나지 않는 변경사항이 처리됩니다. background-color, visibility와 같이 레이아웃에 영향을 끼치지 않는 요소들이 변경될 때 발생합니다.

    중요한 특징은 CRP 과정에서 ReflowRepaint보다 앞에 있기 때문에, Reflow가 발생하면 반드시 Repaint가 동반됩니다.
    무언가를 다시 그린다는 것 자체가 브라우저의 리소스를 잡아먹는 행동이기 때문에, Reflow와 Repaint, 특히 Reflow를 최소한으로 줄일 수 있다면 좋겠죠?

    Repaint시 출처 : https://web.dev/rendering-performance/


    그리고 만약 두 과정이 일어나는지 여부를 파악하고싶다면,
    Chrome Devtool이라는 좋은 기능이 있습니다!
    여러분이 크롬을 사용중이고, F12를 누르면 개발자도구가 나온다는 것은 모두 알고 계실겁니다. 바로 그겁니다!

    여기서 성능(Performance) 탭에 들어가서 녹화 버튼을 누르면, 그 시간동안의 변화사항이 모두 기록됩니다!
    이곳에서 실제로 layout, paint와 같은 과정들을 눈으로 확인할 수 있습니다.

    SsocoTimer에서 버튼에 마우스를 올려놓아서 repaint가 일어나는 상황을 만들어 보았습니다!

     

    2.1. Composite

    Reflow, Repaint 이야기하다가 잠깐 샜네요..?!
    그렇다면 최적화에 있어서 가장 좋은 것은 뭘까요?
    바로 두 과정을 모두 생략하는 것입니다.
    어떻게 그런 일이 발생할 수가 있냐고 물어보실 수 있겠죠?!
    앞에서 잠깐 언급한 Composite 과정이 존재하기 때문입니다.
    변동사항을 Composite에서 처리하게 하는 것이죠!

    위에서 2번이나 본 사진을 다시 가져오겠습니다.

    또 다시 보는 Life of a Pixel / 출처 : https://docs.google.com/presentation/d/1boPxbgNrTU0ddsc144rcXayGA_WF53k96imRH8Mp34Y/edit#slide=id.ga884fe665f_64_1800


    Composite 과정은 GPU가 담당합니다.
    그렇다면 GPU는 무엇을 렌더링하는걸까요??
    데이터가 화면에 그려지기 까지의 과정을 담은 또 다른 사진(The Compositing Forest)을 하나 가져왔습니다.


    ❗ 아래 사진에서 나와있는 일부 정보는 Slimming Paint에 의해 변경될 가능성이 있다는 점을 미리 말씀드립니다!
    - 설명은 변경된 내용으로 진행되니 참고하세요!

     

    Slimming Paint (a.k.a. Redesigning Painting and Compositing)

    Slimming Paint (a.k.a. Redesigning Painting and Compositing) Paint team project to re-implement the Blink<->cc picture recording API to work in terms of a global display list rather than a tree of cc::Layers (~aka GraphicsLayer in Blink terminology). It wi

    www.chromium.org



    우리가 지금까지 위에서 지나온 과정들을 통해서 DOM과 CSSOM을 생성하고, Render Tree를 만들고, 그 Render Tree를 이용해서 화면에 표현될 레이어를 생성하게 됩니다.
    각 DOM 요소, Layout Object(Render Object)들은 화면에 뿌려주기 위해서 레이어형태로 만들어지게 되는데, 이것이 바로 Paint Layer(Render Layer)입니다.

    Slimming Paint가 적용되지 않은 Compositing Forest 사진 / 출처 : https://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome/?spm=a2c65.11461447.0.0.5c88790bSKVvC1



    그리고 Paint Layer의 경우 동일한 좌표공간을 가지는 경우 동일한 Paint Layer를 가지게 됩니다.
    하지만 필요에 따라 다음과 같은 특수 조건을 만족하면 Layer를 여러 개의 층으로 쌓아서 구성할 수 있습니다.
    새로운 layer가 생성되는 경우는 아래와 같습니다. (아래 적은 것 이외에도 더 다양한 요소들이 있습니다!)

    • Root Element인 경우
    • 명시적인 position 속성값을 가지고 있는 경우
    • 투명도가 1 미만인 경우
    • filter, mask, transform, mix-blend-mode를 가진 경우
    • backface-visibility attribute가 hidden인 경우
    • auto가 아닌 column-count, column-width 속성을 가진 경우
    • reflection 속성을 가진 경우


    이렇게 layer 형태로 만든 요소들은 composite 과정에서 순서대로 합쳐져서 우리 화면에 보여지게 됩니다.

     

    Chrome Devtool의 layer 패널에서 이 블로그를 확인한 모습


    그런데!! 여기서 뜬금없이 Graphics Layer가 등장합니다.
    이 그래픽레이어는 바로 GPU에게 CPU가 할 일을 떠넘기는 것이라고 볼 수 있습니다. (GPU가 처리하는 레이어가 바로 Graphics layer!!!)
    아무래도 CPU 혼자서 처리하는 것보다는, GPU의 도움을 받는다면 훨씬 더 빠르게 렌더링 작업을 처리할 수 있겠죠?
    이것이 바로 어딘가에서 줏어들었을 수 있는 하드웨어 가속의 예 중 하나입니다.

     

    출처 : Romain Guy&amp;amp;rsquo;s Android Accelerated Rendering Google I/O 2011


    그럼 또 언제 GPU에게 할 일을 떠넘기냐?!!

    • video나 canvas 태그를 사용하는 경우
    • 하드웨어 가속 플러그인을 사용하는 경우
    • 3d transform 속성이 존재하는 경우
    • backface-visibility attribute가 hidden인 경우 (위에서 봤죠?!)
    • transition, animation 속성이 있는 경우
    • will-change를 설정한 경우 (opacity, transform, top, left 등..)


    등이 존재합니다. (물론 이외에도 다양한 이유들이 있습니다)

    이렇게 GPU가 담당하는 부분이 생기면 CPU가 할 일은 당연히 줄어들겠죠?
    여기서 Reflow나 Repaint가 발생할 수 있는 일들을 처리한다면, 해당 과정이 생략되고 Composite만으로 해결할 수 있기 때문에 더 효율적인 렌더링이 될 수 있는 것이죠!!!


    하지만 장점만 있는 것은 아닙니다.
    당연히 단점도 존재하죠!

    이렇게 GPU가 일을 처리하기 위해서는 많은 준비작업들이 동반됩니다.
    결국 CPU에서 처리하던 일을 GPU에서 처리하기 위해서 데이터를 CPU의 메모리에서 GPU의 메모리로 이동시켜야 합니다. 그 과정에 들어가는 시간을 고려할 필요가 있습니다.
    또한 메모리가 충분하지 않은 경우 데이터가 손실될 가능성이 존재합니다.
    그리고 Layer가 새롭게 생성됨으로써 메모리를 과도하게 사용할 수 있다는 단점도 존재합니다.

    결국 사용에는 이것 저것 많이 따져봐야 한다는 것이죠.

    이와 관련된 부분은 주제를 다소 벗어나는 부분이 있어서, 아래에 좋은 글을 첨부합니다.

     

     

    CSS GPU Animation: Doing It Right — Smashing Magazine

    This article aims to help you to better understand how the browser uses the GPU to render, so that you can create impressive websites that run quickly on all devices.

    www.smashingmagazine.com

     


    3. transform의 특징

    너무 복잡하게 돌아온 부분이 없지 않아 있습니다만, 이제 본 포스팅의 제목인 blink 엔진에서 transform 속성이 Reflow와 Repaint를 발생시키지 않는다는 것에 대해서 조금만 더 알아봅시다!

    만약 position을 absolute로 만들고 left 속성을 이용해서 왼쪽으로 요소를 이동시킨다면, 브라우저는 요소의 위치값이 변경됨에 따라 계속해서 요소의 위치를 계산할 것입니다.
    이 말은 Reflow가 발생한다는 말과 같겠죠?!

    또 변경된 위치를 화면에 그려주기 위해서 Repaint 과정이 일어날 것입니다. (Reflow가 일어났으니 Repaint는 필수불가결적으로 일어납니다!)

    여기서 transform이 등장한다면 어떨까요?
    transform을 사용하게 되면 별도의 layer가 생성됩니다.
    그리고 해당 부분을 animation이나 transition으로 변경시켜준다면 어떨까요?

    이 요소는 GPU가 처리하는 Graphic Layer 영역에 들어가게 되고, Composite과정에서 처리되기 때문에 Reflow와 Repaint과정 없이 처리됩니다.

     

    SsocoTimer의 util icon 버튼들에 먹여진 속성들


    GPU의 역할을 다시 한번 정리해보죠.


    GPU는 이미지를 매우 빠르게 합성할 수 있는데다가, 서브픽셀 보정(subpixel-precision)이라는 애니메이션 보정 기능도 가지고 있습니다.
    이렇게 GPU를 사용해서 Composite 과정을 최적화하기 위해서는 CSS 속성이 문서 배치 방식(document flow)과 연관이 없어야하고, Repaint를 일으키지 않아야 합니다.
    이 조건을 만족하는 CSS 속성이 바로 transformopacity입니다.

    순수하게 두 속성을 사용한다면 CPU의 도움을 받지 않고 GPU만으로 변경사항을 처리할 수 있는 것이죠!

     

    pixel vs subpixel-precision / 출처: https://ko.m.wikipedia.org/wiki/%EB%9E%98%EC%8A%A4%ED%84%B0%ED%99%94



    실제로 이런 CSS 속성들이 어떤 side-effect를 발생시키는지에 대해서 잘 나와있는 csstriggers 라는 사이트가 있습니다.
    이곳을 확인해보면 렌더링 최적화에 대해 더 심도 깊은 고민을 하면서 개발을 진행하실 수 있을 것이라고 확신합니다 :)

     

     

    CSS Triggers

    @PROPERTY_DESCRIPTION@ B G W E Change from default B G W E Subsequent updates

    csstriggers.com


    해당 사이트에서 transform 속성을 살펴보면 아래와 같습니다.

     

    출처 :&amp;amp;nbsp;https://csstriggers.com/transform


    여기서 제가 왜 "blink 엔진에서 transform 속성이 reflow와 repaint를 발생시키지 않는다는 것" 이라고 했는지 드러납니다.

    위에 있는 알파벳이 의미하는 것이 바로 브라우저의 렌더링 엔진 이름입니다.
    Blink의 B, Gecko의 G, Webkit의 W, EdgeHTML의 E가 각각 나와있는 모습을 볼 수 있습니다.

    이 말은 Webkit을 렌더링 엔진으로 사용하는 사파리에서는 transform 속성이 reflow를 일으킨다는 것이겠죠?
    이렇게 렌더링 엔진마다 다를 수 있는 부분에 대해서는 항상 체크를 할 필요가 있습니다.


    (TMI : 노파심에 추가로 말씀드리자면, transform만 있는게 아니라 다른 Reflow나 Repaint를 발생시키는 요소가 해당 레이어에 함께 들어가게 된다면, 당연히 Reflow나 Repaint가 발생하게 됩니다!!)


    4. 결론

    예시를 그다지 많이 들지 않았음에도 포스팅이 꽤나 길어졌다는 점.. 양해 부탁드립니다 ㅠㅠ
    최대한 쉽게 써보려고 했는데 쉽지가 않네요..

    그래서 이번 포스팅을 통해 알게된 점은 아래와 같습니다.

    • 렌더링 최적화에 있어서 transform 속성은 굉장히 유용할 수 있다는 점,
    • 그렇다고 해서 transform을 사용함으로써 GPU를 이용한 composite 과정을 거치는 것이 항상 최적의 결과를 불러오는 것이 아니라는 것을 알 수 있었습니다.

     


    5. 참고자료

     

    How Blink works

    How Blink works bit.ly/how-blink-works Author: haraken@ Last update: 2018 Aug 14 Status: PUBLIC Working on Blink is not easy. It's not easy for new Blink developers because there are a lot of Blink-specific concepts and coding conventions that have...

    docs.google.com

     

    Front-End Performance Optimization with Accelerated Compositing Part 1

    Optimizing the performance of any webpage is crucial. This blog gives an insight into the overall process of reforming the whole display and layout of any webpage with accelerated compositing.

    www.alibabacloud.com

     

    renderer/core/paint

    renderer/core/paint The code in this directory converts the LayoutObject tree into an efficient rendering format for the compositor (a list of cc::Layers containing display item lists, and associated cc::PropertyTrees). For a high level overview, see the O

    chromium.googlesource.com

     

    Constructing the Object Model

    Learn how the browser constructs the DOM and CSSOM trees.

    web.dev

     

    Rendering Performance

    Users notice if sites and apps don't run well, so optimizing rendering performance is crucial!

    web.dev

     

    프론트엔드 개발자를 위한 크롬 렌더링 성능 인자 이해하기

    3년 전에 개인 블로그에 적었던 글이라 이미 보신 분들도 있으리라 생각됩니다만, 미디엄에서 이전의 기술관련 글들을 같이 관리할 겸 같이 포스팅하기로 하였습니다. :)

    medium.com

     

    Inside look at modern web browser (part 3) - Chrome Developers

    Inner workings of a browser rendering engine

    developer.chrome.com

     

    CSS GPU Animation: Doing It Right — Smashing Magazine

    This article aims to help you to better understand how the browser uses the GPU to render, so that you can create impressive websites that run quickly on all devices.

    www.smashingmagazine.com

     

    [CSS] opacity는 reflow가 발생 안 한다구요...? 정말??

    0. 왜 이 포스팅을 쓰게되었는지에 대하여. 이 포스팅은 계획에 없던 포스팅이다. 사실 CSS Triggers에 대한 포스팅은 저번 포스팅으로 끝내려고 했었다. 근데 왜 또, 포스팅을 작성하고 있냐...면,

    blinders.tistory.com

     

    CSS Triggers

    @PROPERTY_DESCRIPTION@ B G W E Change from default B G W E Subsequent updates

    csstriggers.com

    https://d2.naver.com/helloworld/59361
    https://d2.naver.com/helloworld/2061385
    https://d2.naver.com/helloworld/5237120

    반응형
    • 네이버 블로그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기