이 블로그는 크로뮴, Gecko 환경에서 제일 잘 작동됩니다.
profile

글루미스토어

프론트엔드 개발 블로그입니다. Nextjs 14로 개발되었습니다.

[FE 최적화] CSS transform은 정말로 reflow를 하지 않을까?

my Blog!

[FE 최적화] CSS transform은 정말로 reflow를 하지 않을까?

조회수: 113[운영자]영이







프론트엔드 최적화에 대해 배울 즈음,

다들 transform의 비용이 저렴하다는 것을 듣게될 것이다.



reflow-chart.png

출처: https://developers.google.com/speed/docs/insights/browser-reflow?hl=ko


실제로 구글 공식 문서에서도 reflow에 대한 비용을

브라우저 별로 표시해두었을만큼 css 속성에 대한 성능은 천차만별인데,


transform으로 일어나는 모든 일은 이 reflow를 건너뛴다는 말이니 

위 계산 자체가 필요하지 않다.

(사실 위의 표대로 css속성이 얼마나 비용이 드는지 외우고 있는 개발자도 없을거고...)


이것이 사실인지 알아보도록 하자.







<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Animation Performance Test</title>
    <style>
        /* 일반적인 CSS 애니메이션 (width와 height 변경) */
        .box-animate {
            width: 100px;
            height: 100px;
            background-color: red;
            margin: 10px;
            transition: width 1s ease-in-out, height 1s ease-in-out;
        }

        .box-animate.active {
            width: 200px;
            height: 200px;
        }

        /* transform을 사용하는 애니메이션 */
        .box-transform {
            width: 100px;
            height: 100px;
            background-color: blue;
            margin: 10px;
            transition: transform 1s ease-in-out;
        }

        .box-transform.active {
            transform: scale(2);
        }

        /* 버튼 스타일 */
        button {
            margin: 20px;
            padding: 10px;
            font-size: 16px;
        }
    </style>
</head>
<body>
    <h1>Reflow와 Paint를 비교하는 애니메이션</h1>

    <button onclick="toggleAnimation()">일반 CSS 애니메이션 (Reflow 발생)</button>
    <button onclick="toggleTransform()">Transform 애니메이션 (Reflow 없음)</button>

    <div class="box-animate" id="box-animate"></div>
    <div class="box-transform" id="box-transform"></div>

    <script>
        function toggleAnimation() {
            const box = document.getElementById('box-animate');
            box.classList.toggle('active');
        }

        function toggleTransform() {
            const box = document.getElementById('box-transform');
            box.classList.toggle('active');
        }
    </script>
</body>
</html>


원하는 사람은 위 HTML을 간단하게 복사해서 사용할 수 있다.








브라우저에서 [성능] 탭을 클릭한 뒤

녹화 버튼을 누르면 실제로 어떤 rendering 과정이 일어났는지 볼 수 있다.









1.jpg


우선 빨간 박스는

우리가 잘 아는 width를 변경하는 식으로 animation을 구현했다.




1.jpg



사전 페인트 -> hit test -> 스타일 다시계산 예약 -> 스타일 다시계산 -> 레이아웃 -> 사전페인트 -> 페인트 -> 계층화 -> 커밋


저 "작업" 아래에 있는 곳이

실제 무슨 과정이 일어났는지 상세하게 적혀있는 곳인데,

크롬 브라우저에서는 실제로 reflow라는 용어를 사용하는 것은 아니고 레이아웃이라고 원래의 용어 그대로 사용한다.


아래에서 더 설명하겠지만,

작업 내내 GPU가 일을 한다.






1.jpg


파란 박스는 transform으로 scale(2)를 적용하는 방식으로 구현했다.







2.jpg


 | | | | 바코드처럼 되어있는 부분은 "작업" 그 자체를 나타내는 것이고,

아마 모니터 주사율에 따라 실제로 화면에 그리는 것을 나타내고 있는 듯 하다.


빨간 박스 animation과는 달리,

몇몇 GPU 작업을 제외하면 부가적인 작업이 존재하지 않는다.


즉, GPU 가속작업도 최소화 된다는 것으로 해석된다.











3.jpg



빨간 박스는 reflow를 계속해서 일으키며

GPU도 계속 사용하는 반면(수백번),


파란 박스는 아주 가끔 (1초에 3~4번 정도)을 제외하면 

렌더링 엔진이 일을 별로 하지 않는다는 결론에 도달했다.


transform의 경우에는 gpu가 미리 계산을 다 해두고 

blink 자체는 계산되어있던 값을 시간마다 그저 보여주기만 할 뿐이라 해석된다.




당연하다면 당연하지만,

transform으로 일어난 애니메이션은 주변 요소에 영향을 주지 않기 때문에 

저런 단순한 계산과 과정으로 구현이 가능한 것이고,


이외의 CSS속성으로 애니메이션을 만들면

주변 요소에 영향을 미치기 때문에 

요소의 위치, 레이어 등을 다시 계산해야하는 것이다.


다만 주변 요소에 영향을 미치지 않고 애니메이션을 일으켜야하는 화면 기획 자체가 

나의 실무 경험상 거의 없었기 때문에 

이를 적용시키는 것은 제한적이 될 것으로 보인다.












댓글: 0