본문 바로가기

FrontEnd

CSS 애니메이션 성능 분석 및 개선하기

반응형

원글번역한 글을 학습한 내용을 정리한 글 입니다.

 

Performance monitoring in CSS animations

Animation using JavaScript ? or Animation using CSS?

medium.com

CSS 애니메이션은 일부 속성에 의존함

  • position : absolute / relative
  • transform
  • opacity
  • left, right, top, bottom 등등…

성능 측정 결과를 이해하는 방법

웹 브라우저의 렌더링 방식을 간단히 살펴보겠습니다.
웹 브라우저는 UI를 다음과 같은 방식으로 생성합니다.

  1. Recalculate Style
    요소에 적용할 스타일을 계산.
  2. Layout
    요소의 레이아웃을 생성하고, 화면에 배치.
  3. Paint
    생성된 모든 레이아웃에 픽셀을 추가. GPU는 필요에 따라 생성한 레이어의 비트맵을 사용해 화면에 렌더링.
  4. Composite Layers
    생성한 레이어 계층을 합성. 이 계층을 내려다보면 모든 요소가 고유한 위치(복합 계층)를 갖는 완전한 웹 페이지로 보여집니다.

Composite Layers 생성은 CPU가 애니메이션을 처리하기 위해 GPU와 통신하는 단계입니다.
transformopacity와 같은 속성을 사용하면, CPU 대신 GPU를 사용해 웹 브라우저가 애니메이션을 수행할 수 있도록 할 수 있습니다.

  • 즉 최적화의 열쇠는 GPU를 사용하는 transform, opacity와 같은 속성
  • 그래픽 태스크에 최적화된 특별한 유닛(GPU) 위에서 진행되는 서브픽셀 보정 덕분에 비단결 처럼 부드러운 애니메이션 효과를 얻게 됩니다.
    • 그리고 이는 매우 빠른 속도로 진행됩니다.
  • 애니메이션이 더이상 CPU에 묶여 있지 않게 됩니다.
    • 매우 복잡스런 자바스크립트 태스크가 돌아가고 있다 하더라도 애니메이션은 여전히 빠르게 진행이 됩니다.

Composite Layers 생성이 트리거되면 새 레이어를 생성합니다.

  • 이것은 UI 요소의 애니메이션과 아닌 일부를 나눠, 다시 렌더링 하지 않기 위해서입니다.
  • GPU는 이 렌더링 객체 트리를 메모리에 유지하고, 다시 렌더링 하지 않는 레이어를 위에 얹을 수 있습니다.

새 레이어 생성은 낭비입니다.

  • translate 대신 position (top, left) 등을 사용하면 새 레이어를 생성합니다.

 

컴포지팅 작업을 최적화 하려면, 애니메이션이 적용되는 CSS 속성이 다음과 같은 상태임을 브라우저가 확실히 알고 있어야 합니다.

  • 문서 플로우에 영향을 미치지 않는다.
  • 문서 플로우와 의존 관계를 맺고 있지 않다.
  • 리페인트를 발생시키지 않는다.
누군가는 top과 left 속성이 absolute와 fixed 속성처럼 요소가 위치한 환경과 관련이 없다고 생각할 지도 모르나,
실상은 그렇지 않습니다.

예를 들어 left 속성은 .offsetParent 크기에 따른 퍼센트 값을 속성값으로 지닐 수도 있습니다.
혹은 em, vh 등등 환경에 영향을 받는 단위로 값이 설정될 수도 있습니다.

위에서 나열한 조건에 일치하는 CSS 속성은 오로지 transformopacity 뿐입니다.

성능 분석 실습

원문의 예제를 풀스크린으로 접속

https://wit-blog.github.io/cssanimation_samplecode/

 

[YEONG9] CSS Animation

 

wit-blog.github.io

translate일 경우는 conposite layer 만 반복하는 것을 볼 수 있음 [main thread[
스타일 재계산부터 레이아웃 작업이 주기적으로 발생함

  • translate를 사용하면 composite layer만 사용해, 기존 레이어들을 해당 위치에 쌓는 방식으로 기존 레이어를 재사용할 수 있습니다.
  • 레이아웃 시프트가 발생하면, 처음부터 다시 렌더링(스타일 재계산부터)해야 하므로 성능 낭비가 발생합니다.

스타일 재계산이 얼마나 자주 발생하나요?

top / left

레이아웃과 스타일 재계산이 계속해서 발생합니다.

퍼포먼스 모니터와 레이어 페인트 카운트를 보면 얼마나 자주 리렌더링이 일어나는지 확인할 수 있습니다.

translateX

레이아웃과 스타일 재계산이 거의 발생하지 않습니다.

암묵적 컴포지팅

아직 컴포짓 레이어에 올라가지 않은 요소가 하나 이상 존재할 때, 쌓임 순서(stacking order) 때문에 이들이 컴포짓 레이어 위에 존재하는 요소보다 위에 와야 하는 경우, 이 요소들 때문에 컴포짓 레이어가 추가적으로 생성됩니다.

별도의 이미지로 페인팅 되어서 GPU로 보내지게 되는 것이죠.

https://codepen.io/sergeche/pen/jMeegL

 

GPU article: repaint on start-end

...

codepen.io

위에서 play를 눌러보면, 애니매이션 도중에 컴포짓 레이어가 생성되는 것을 볼 수 있습니다.

  • 애니메이션이 빠르고 부드럽다 (60FPS).
  • 적절히 신경써서 만든 애니메이션은 독립된 스레드 상에서 재생된다. 또한 이는 무거운 자바스크립트 코드 연산 때문에 방해를 받지 않는다.
  • 3D 트랜스폼은 비용이 “싸다”.
  • 컴포짓 레이어에 요소를 올리려면 추가적인 리페인팅 작업을 해야 한다. 때때로(추가된 것만 그리는 대신에 레이어 전체를 리페인팅 해야 할 때) 이 과정은 매우 느리게 진행된다.
  • 페인팅 처리된 레이어는 GPU로 보내져야 한다. 이 레이어의 크기와 갯수에 따라 전송 과정 역시 매우 느려질 수 있다. 그 결과로 중저가 기기에서 요소 깜빡임이 발생할 수 있다.
  • 모든 컴포짓 레이어는 추가적으로 메모리를 소모한다. 메모리는 모바일 기기에서 매우 귀중한 자원이다. 메모리 과다 사용은 브라우저 충돌을 일으킬 수 있다.
  • 암묵적 컴포지팅을 고려사항에 넣지 않는다면, 느린 리페인팅, 초과 메모리 사용 및 브라우저 충돌이 발생할 가능성이 매우 높다.
  • 사파리 텍스트 렌더링처럼 부자연스런 시각 요소가 나타날 수 있으며, 일부 경우 페이지 컨텐츠가 사라지거나 왜곡되어 나타날 가능성이 있다.

 

암묵적 컴포지팅과 부자연스러운 시각 요소 발생을 막으려면 다음과 같은 방법을 적용해 보는 것을 추천드립니다.

  • 애니메이션 처리된 오브젝트의 z-index 값을 최대한 높게 유지되도록 해봅니다. 이 요소들이 body 요소의 직계 자식 요소이면 이상적인 환경입니다. 당연히, 애니메이션 요소들이 DOM 트리 깊숙하게 위치해 있고 일반적인 흐름(normal flow) 위에 위치해 있다면, 마크업 구조로 보았을 때 항상 가능하지는 않은 얘기입니다. 이런 경우에는 요소를 복제해서 애니메이션만을 위해 body의 자식 요소로 넣어 보는 시도를 해볼 수 있습니다.
  • 브라우저에게 will-change CSS 속성을 사용해 내가 이제 컴포지팅을 할 예정이라고 귀뜸해 줄 수 있습니다. 이 속성이 요소에 적용이 된 상태라면, 브라우저는 이 요소를 사전에 컴포짓 레이어 위에 올려 두기 때문에, (그런데 항상 이러지는 않습니다!) 원활하게 애니메이션이 시작하고 멈출 수 있도록 만듭니다. 그러나 이 속성을 오용하지는 마세요. 만약 그렇게 한다면, 메모리 사용량이 무지막지하게 증가해 버립니다!

참고

https://wit.nts-corp.com/2017/08/31/4861

 

CSS GPU 애니메이션 제대로 하기 | WIT블로그

컴포지트 레이어에 대한 이해 및 CSS에서 GPU처리에 대한 전반적인 이해를 다룹니다

wit.nts-corp.com

https://wit.nts-corp.com/2017/06/05/4571

 

CSS 애니메이션 성능 개선 방법(reflow 최소화, will-change 사용) | WIT블로그

CSS 애니메이션 성능 개선 방법(reflow 최소화, will-change 사용)

wit.nts-corp.com

 

반응형