애니메이션 성능 최적화

dahyeon·2023년 5월 1일
0
post-thumbnail

애니메이션 렌더링 성능 최적화라고 하면 ‘transform, opacity 속성만 변경하면 CPU가 아닌 GPU에서 처리하기 때문에 리플로우가 일어나지 않아서 더 빠르다더라~’ 정도만 알고 있었다. 프로젝트를 진행하면서 애니메이션 성능을 개선해야 할 일이 생겼고, 그 과정에서 애니메이션 성능을 결정하는 요소와 성능 최적화 방법을 정리해보았다.

시작하기에 앞서, 구체적인 브라우저의 렌더링 과정을 먼저 이해하고 있으면 좋다(링크).

애니메이션 성능 최적화의 key 아이디어

  • 레이아웃을 다시 계산하는 작업(리플로우)은 구현 비용이 크다. 따라서 최대한 레이아웃에 영향을 끼치지 않는 요소를 사용해서 애니메이션을 구현해야 한다.
    • 레이아웃에 영향을 끼치지 않는 요소로는 대표적으로 transform과 opacity가 있다.
  • 브라우저는 레이아웃에 영향을 끼치지 않는 요소의 애니메이션을 렌더링해야될 때, 2개의 레이어(배경, 움직이는 요소)로 나눈다.

레이어
크롬에서 레이어는 하나 또는 여러 개의 노드로 이루어진 그룹의 내용을 우리가 볼 수 있는 형태인 이미지로 만들기 위한 단위이다.

  • 각 애니메이션 프레임마다 브라우저는 (새로운 요소를 그릴 필요없이) 레이어들을 재배치(re-position)하고, 스냅샷을 찍으면 된다.
  • 이러한 스냅샷을 찍는 과정(snapshotting)을 컴포지팅(compositing)이라고 하며, GPU는 컴포지팅에 최적화되어 있다.

따라서, CPU가 아닌 GPU에서 무거운 애니메이션 관련 작업을 수행하게끔 만들면 우리가 원하는 애니메이션 성능 최적화를 달성할 수 있다. 이를 ‘하드웨어 가속’이라고 한다.

하드웨어 가속

하드웨어 가속
일부 기능을 CPU에서 수행하는 것보다 더 빠르게 수행할 수 있는 하드웨어(GPU)에서 처리하는 것을 말한다.

  • GPU는 수신된 데이터(이미지)를 이용하여 무언가를 그리는데 적합하다.

하지만 하드웨어 가속이 무조건 빠른 것은 아닐 수 있다. CPU가 할 일을 GPU가 대신 처리해주더라도, GPU가 할 일을 지시하고 관리하기 위한 일은 CPU에서 수행되기 때문이다.

  • GPU와 CPU는 메모리를 전혀 다른 공간에서 다루는데, 따라서 GPU에서 사용할 데이터를 CPU에서 처리해서 보내줘야 한다.
    • CPU가 GPU에서 사용할 데이터를 처리하는데 시간이 걸린다.
    • 물리적으로 완전히 분리되어 있는 메모리 간에 데이터를 전달할 때는 성능 상의 손실이 발생하게 된다.

레이어와 will-change 속성

레이어를 나누는 것이 무조건 좋은가?

  • 레이어는 메모리를 차지한다.
  • 레이어가 너무 많으면 그 만큼 컴포지팅에 오랜 시간이 걸린다.

따라서 브라우저는 필요하다고 생각되는 레이어만 생성한다.

will-change 속성

  • 만약 요소 A에 애니메이션을 나중에 적용해준다고 생각해보자. 브라우저는 애니메이션이 언제 적용될 지 모르기 때문에, A를 별도의 레이어로 분리해야된다는 것을 알지 못한다.
  • 이 경우 A에 애니메이션이 적용되면 기존에 하나의 레이어였던 것을 두 개로 분리하고, 다시 그리는 데 시간이 소요될 것이다.
  • 따라서 브라우저에게 이 요소가 변경될 것임을 알려주어 최적화를 할 수 있도록 도와주는 것이 will-change 속성이다.

하지만 앞서 말했듯 레이어를 나누는 것이 무조건 좋은 것은 아니다. 오히려 불필요하게 적용했을 때 성능 저하가 발생할 수 있다.

  • 공식 문서에서도 will-change 속성은 마지막 수단으로 생각해야 하고, 성능 저하가 심해서 개선해야 되는 경우가 아니라면 사용을 지양할 것을 권장하고 있다.

CSS Animations vs Web Animations API

애니메이션을 구현하는 방법에는 크게 두 가지: CSS Animations 와 Javascript Animations인 Web Animations API가 있다.

Web Animations API의 현재 지원 범위는 다음과 같다.

Web Animations API의 간단한 사용 예시

  • Web Animations API는 DOM 요소의 animate 함수를 실행하고, 첫 번째 인수로 keyframes를, 두 번째 인수로 options를 넘겨준다(링크).
animate(keyframes, options)
document.getElementById("alice").animate(
  [
    { transform: "rotate(0) translate3D(-50%, -50%, 0)", color: "#000" },
    { color: "#431236", offset: 0.3 },
    { transform: "rotate(360deg) translate3D(-50%, -50%, 0)", color: "#000" },
  ],
  {
    duration: 3000,
    iterations: Infinity,
  }
);

Web Animations API의 장점

  • 애니메이션 성능 최적화: 레이아웃의 변경이 없는 애니메이션이 컴포지터에서 수행되도록 한다.
  • 애니메이션을 스타일시트가 아닌 자바스크립트 코드에 작성함으로써 behavior(행위)와 presentation(표현)을 분리할 수 있다.
  • 동적으로 값을 지정해서 사용할 수 있다.
    • 예시
      const moveUpAnimation = [
          {opacity: '1', transform: 'translateY(0) translateX(0)'},
          {opacity: '0', transform: `translateY(-50px) translateX(${getRandomTranslateX()})`},
      ]
  • 애니메이션을 한꺼번에 실행하고 중지하거나, 애니메이션을 거꾸로 돌리는 등의 컨트롤이 가능하다.

그래서 Web Animations vs CSS Animations ?

  • 성능의 관점에서, CSS Animations를 사용할 때에도 레이아웃에 변경이 없는 요소를 사용하고, will-change 속성을 적절히 이용하면 성능 최적화를 이룰 수 있다.
    • 필자가 직접 프로젝트를 진행하면서 성능 비교를 했을 때 눈에 띄는 성능 차이는 없었다. Web Animations API의 경우 scripting에 좀 더 시간이 걸리고, CSS Animations의 경우 rendering에 좀 더 시간이 걸린다. 합쳐보면 Web Animations API가 좀 더 앞서는 정도였다. (당연히 상황에 따라 다를 수 있다.)
  • 애니메이션을 컨트롤해야 하거나, 애니메이션 내에서 동적으로 값을 지정해야 할 때 Web Animations API가 더 적합하다.
  • 간단하고, UI 요소에 한정된 상태들이라면 CSS Animations가 더 적합하다.

참고 자료
Animating like you just don’t care with Element.animate – Mozilla Hacks - the Web developer blog
프론트엔드 개발자를 위한 크롬 렌더링 성능 인자 이해하기
will-change - CSS: Cascading Style Sheets | MDN
Using the Web Animations API - Web APIs | MDN
CSS versus JavaScript animations

profile
https://github.com/dahyeon405

0개의 댓글