1. Left 애니메이션은 왜 끊길까?
transform
,left
속성으로, 대각선 방향으로 움직이는 공 애니메이션을 만들어봤다.
See the Pen Animate with Translate and left by KumJungMin (@kumjungmin) on CodePen.
- 보기에는 둘 다 잘 동작하는 거 같은데, 만약 JS에서 복잡한 연산을 실행하면 어떻게 될까?
- gif를 보면 알 수 있듯이 JS에서 복잡한 연산을 하자,
left
애니메이션이 잠시 끊기는 걸 볼 수 있다.
- 그럼 두 애니메이션의 성능은 어떨까? [Chrome] > [성능]에서 성능을 측정해보았다.
transform
애니메이션의 경우 별다른 성능 이슈가 없는 것으로 보인다.
- 그에 반해
left
애니메이션은 “누적 레이아웃 변경으로 사용자 경험이 악화”된다는 경고가 떴다.
🤔 그럼 어떻게 해야
left
애니메이션의 성능을 올리고, 애니메이션 끊김을 막을 수 있을까?
- 답은 간단하다!
left
속성을transform
으로 바꾸면 된다. - 그럼, 왜
transform
애니메이션은 끊김 현상이 없고, 성능 이슈도 없을까? - 이유는
transform
애니메이션이 GPU에서 작동하고, 리플로우(Reflow)가 발생하지 않기 때문이다. - 이번 시간에는 GPU와 리플로우 관점에서,
transform
애니메이션의 성능이 좋은 이유를 알아보았다.
2. transform 애니메이션은 왜 성능이 좋을까?
1) GPU 관점에서 살펴보기
🤔
left
애니메이션은 CPU에서 처리하고,transform
애니메이션은 GPU에서 처리한다.
그리고 GPU 기반 애니메이션은 성능이 좋다고 한다.
그러면 CPU와 GPU는 어떤 차이가 있길래, GPU 애니메이션의 성능이 더 좋을까?
(1) CPU와 GPU의 특징
- CPU와 GPU 차이는 아래 표를 보면 알 수 있는데, CPU는 논리적 연산에 최적화 되어있지만 GPU는 그래픽 처리에 최적화되었다.
종류 | CPU (Central Processing Unit) | GPU (Graphics Processing Unit) |
---|---|---|
장점 | - 범용적인 연산에 최적화 - 복잡한 연산, 논리적인 처리, 순차적인 작업에 적합 |
- 그래픽 처리에 특화된 프로세서 - 수천 개의 작은 코어를 가지고 있어 대량의 병렬 연산에 적합 - 비디오 렌더링, 이미지 처리를 빠르게 처리할 수 있음 |
단점 | - 한 번에 처리할 수 있는 작업의 양이 제한적 - 많은 양의 병렬 처리에는 적합하지 않음 |
- 남용시 성능 저하를 일으킴 - CPU 렌더링에 비해 정확성이나 품질이 낮음 |
- CPU 기반 CSS 속성은
left
,right
,width
,height
등이 있고, - GPU 기반 CSS 속성은
transform
,opacity
등이 있다.
(2) GPU 애니메이션이 빠른 이유
- CPU는 메인스레드 작업을 담당하고 순차적인 작업에 적합하다.
- 그렇다보니, CPU가 다른 연산을 처리 중이면 CPU 기반 애니메이션은 동작이 멈출 수 있다.
- 사용자 입장에서는 애니메이션이 끊기거나 멈추는 것처럼 보여 사용성을 해친다.
- 그래서 그래픽이나 애니메이션 작업은 메인 스레드와 별개로, 병렬로 처리되는 게 좋다.
- GPU는 병렬 작업에 최적화되어 있으며, 메인 스레드와 별개로 애니메이션을 처리할 수 있다.
- 그래서 GPU로 애니메이션을 처리하면, CPU는 그래픽이 아닌 다른 계산을 처리할 수 있어 성능을 유지할 수 있다.
- 결국 GPU 기반 애니메이션은 메인 스레드와 별개로 병렬 처리할 수 있어 성능이 좋다!
2) Reflow 관점에서 살펴보기
💡
left
,right
등 CPU 기반 애니메이션은reflow
가 발생해 애니메이션 성능이 좋지 않다.
어? 그런데reflow
는 무엇이길래 성능에 영향을 주는 걸까?
(1) Reflow, 화면 레이아웃을 다시 그리는 작업!
reflow
을 이해하기 위해선, 브라우저 렌더링 과정을 알아야한다.
단계 | 설명 |
---|---|
Style |
1. 유저가 브라우저에 입장하면, 네트워크에서 브라우저 리소스를 다운로드 받는다. 2. 그 다음, 리소스(HTML, CSS)를 파싱해서 각각 DOM 트리, CSSOM 트리를 만든다. 3. DOM 트리, CSSOM 트리를 결합해 Render Tree(렌더트리)를 만든다. |
Layout |
4. 브라우저는 생성된 렌더트리를 기반으로 노드의 크기나 위치를 계산한다. |
Paint |
5. 노드를 화면에 그리는 단계이다. 경우에 따라 화면에 그리는 작업을 몇 개의 레이어로 나눠 진행한다. (이 경우는 다음 섹션에서 설명) |
Composite |
6. 만약 레이어 분리가 일어났다면 레이어를 하나로 합친다. |
- 여기서 주목한 곳은
Layout
인데, 왜냐하면reflow
가 이Layout
을 다시 하는 걸 말하기 때문이다. reflow
가 발생한다는 건, 요소의 크기, 위치 계산을 다시 한다는 말이다.
💡 요소의 위치나 화면을 다시 그릴 수도 있지, 왜 이 작업이 성능에 영향을 주나요?
reflow
는 DOM 요소의 기하학적 속성이 변경되거나, 브라우저 사이즈가 변할 때 발생한다.- 그리고 비용 큰 이유는,
reflow
가 발생하면 주변 요소의 위치나 크기에도 영향을 주기 때문이다. - 아래 이미지를 보면 알 수 있듯이, 형제 2의 너비가 변경되자 형제 3의 위치도 영향을 받았다.
- 이처럼
reflow
는 주변 요소의 위치나 크기에도 영향을 주기에 비용이 높다. - 또한
reflow
가 발생하면, 재생성된 렌더트리를 기반으로repaint
(Paint
다시하기)도 한다;
💡 아하! 결국
left
,right
와 같은 속성으로 애니메이션을 만들면reflow
가 발생해,
주변 요소의 위치나 크기에 영향을 주고Paint
도 발생해서 성능이 안 좋은거구나!
- 그러면 여기서 하나의 의문이 생긴다. GPU 애니메이션은 왜
reflow
이 안 일어날까? - 그 이유는 GPU 애니메이션은 별도 레이어에서 처리되기 때문이다!
(2) 별도 레이어에서 처리된다고?
- 브라우저는
Paint
단계에서 아래 태그나 속성을 만나면, 노드를 별도 레이어로 분리한다.
- 태그
<video></vide>
<canvas><canvas>
- CSS 속성
opacity
transform
will-change
- 노드가 별도 레이어로 분리되면 다른 요소에 영향을 주지 않아
reflow
가 발생하지 않는다. - 그리고 레이어는 CPU가 아닌 GPU에서 처리되기에 메인 쓰레드의 부담이 적어 성능이 보장된다.
- 결국,
transform
애니메이션은 별도 레이어에서 처리되므로,reflow
가 발생하지 않는 것이다.
2. 마치며…
- 이번 시간에는
transform
애니메이션 성능이 좋은 이유를 알아보았다. - 첫 번째 이유는
transform
애니메이션이 GPU를 사용하여 병렬 처리가 되기 때문이었고, 두 번째 이유는 별도의 레이어에서 처리되Reflow
를 발생시키지 않기 때문이었다. - 단, GPU 기반 애니메이션은 이처럼 성능이 좋다는 이점도 있지만 주의할 점이 있다.
- 첫째, GPU 애니메이션을 남용하면 GPU 메모리 사용량이 증가해 메모리 리소스가 고갈될 수 있다.
- 둘째, 레이어를 많이 만들면 GPU가 관리해야 할 레이어가 증가하여 성능 저하를 초래할 수 있다.
- 셋째, 레이어를 합성하는 과정이 추가되면서 전체 렌더링 시간이 늘어날 수 있다. 따라서, GPU 애니메이션은 필요할 때만 적절히 사용하는 것이 중요하다.
+) 출처
- https://www.sitepoint.com/introduction-to-hardware-acceleration-css-animations/
- https://www.algolia.com/blog/engineering/performant-web-animations/
- https://web.dev/articles/animations-overview?hl=ko#pipeline
- https://web.dev/articles/rendering-performance?hl=ko
- https://developer.mozilla.org/ko/docs/Web/Performance/How_browsers_work
반응형
'개발 기술 > 사소하지만 놓치기 쉬운 개발 지식' 카테고리의 다른 글
콘텐츠 접근이 가능한 아코디언을 만들어보자! (with. until-found, details) (0) | 2024.02.13 |
---|---|
input 유효성에 따라 스타일링하는 3가지 방법 (invalid, user-invalid, out-of-range) (0) | 2024.01.06 |
키 타입을 보장할 수 있는 Map 객체(주의! array.map 아님) (0) | 2023.10.15 |
[html] 더 나은 사용자 입력을 위한 inputmode 속성 (0) | 2023.08.20 |
[모노레포] 특정 폴더를 패키지화하는 방법 (0) | 2023.05.15 |
댓글