High Performance Animations

HTML5 Rocks

제대로 쫒아가보도록 하겠습니다. 모던 브라우저들은 정말 저비용의 4가지 애니메이션 요소- 위치, (축소/확대) 비율, 회전투명도 -를 가지고 있습니다. 만약 다른 방식으로 애니메이션을 하는 것은 위험을 각오해야 하고, 비단결처럼 부드러운 60fps에 도달할 기회를 잃어버리게 될 것입니다.

Cheap to animate

동일한 애니메이션을 비교하는 슬로우 모션 비디오를 살펴보도록 하겠습니다.

하나는 transforms을 적용했고 다른 하나는 적용하지 않았습니다. 어떤 차이점이 존재하는지 확인하셨다면 이제 왜 저렇게 동작하는지 살펴보도록 하겠습니다.

개발자 도구: DOM부터 픽셀까지

크롬 개발자 도구의 타임라인을 사용하면 다음과 같은 유사한 패턴을 볼 수 있습니다.

DevTools waterfall
크롬 개발자도구의 프레임 모드.

브라우저가 거치는 프로세스는 다음과 같이 상당히 단순합니다. : 엘리먼트에 적용할 스타일의 계산(스타일 재계산), 각 엘리먼트에 대한 기하정보(Geomerty)와 위치의 생성 (레이아웃), 각 엘리먼트에 해당하는 픽셀들을 레이어들에 채우기 (페인트 설정 및 페인트) 그리고 레어를 스크린으로 출력 (레이어들의 합성).

비단결같이 부드러운 애니메이션을 위해 작업을 회피할 필요가 있으며 이를 위한 최선의 방법은 합성(Compositing)에 영향을 주는 속성(transform과 opacity)의 변경만으로 그를 처리하는 것입니다. 보다 좋은 방식은 스크린 상의 픽셀들을 처리하기 위한 추가적인 작업들을 표시해주는 폭포수 형태의 타임라인으로부터 시작하는 것입니다.

이 권장 사항은 폭넓은 브라우저 간의 호환성을 가지고 있습니다. 크롬, 파이어폭스, 사파리 및 오페라 모두에서 transform과 opacity에 대한 하드웨어 가속을 받을 수 있습니다. 불행하게도 인터넷 익스플로러 10 이상 버전의 사용 시 어떠한 규격에 의해 하드웨어 가속을 결정하는지는 명확하지 않습니다. 그러나 IE11에 F12 도구가 탑재되면 보다 확실하게 알 수 있을 것입니다.

레이아웃 애니메이션 속성들

엘리먼트를 변경할 때 브라우저는 변경에 영향을 받는 모든 엘리먼트의 기하값(위치와 크기)을 계산하는 레이아웃 작업을 수행할 필요가 있습니다. 하나의 엘리먼트를 수정해도 다른 엘리먼트들의 기하값의 아마 재계산될 필요가 있을 것입니다. 예를 들어, <html> 엘리먼트의 폭을 변경하면 모든 자식 엘리먼트의 기하값들도 재계산될 수 있습니다. 엘리먼트가 오버플로(overflow)되면 또 다른 엘리먼트에 영향을 주기 때문에 때때로 변경이 트리를 따라 내려가는 것은 레이아웃 계산 시 값들이 모든 경로에서 최상위로 다시 되돌아 올려진 결과일 수 있습니다.

시각적인 엘리먼트들의 트리가 커지면 레이아웃 계산의 수행은 더 길어지게 되기 때문에 레이아웃 작업을 발생하는 속성의 애니메이션을 회피하기 위해 노력해야 합니다.

앱 상태를 <html>나 <body> 엘리먼트에 클래스로 저장하고 계십니까? 이 엘리먼트가 변경될 경우 브라우저는 스타일 계산과 레이아웃을 다시 수행해야 할 겁니다. 여러분의 앱에서 레이아웃의 계산이 갑작스럽게 발생되는지를 검토하세요. 그들이 애니메이션이 되지 않는다고 해도 성능에 아주 큰 영향을 줄 것입니다!

변경되면 레이아웃을 발생하는 가장 많이 사용되는 CSS 속성들은 다음과 같습니다.

레이아웃에 영향을 주는 스타일들

widthheight
paddingmargin
displayborder-width
bordertop
positionfont-size
floattext-align
overflow-yfont-weight
overflowleft
font-familyline-height
vertical-alignright
clearwhite-space
bottommin-height

Source: http://goo.gl/lPVJY6

페인트 애니메이션 속성들

엘리먼트의 변경은 또한 페인팅을 발생하며 모던 브라우저에서 대다수의 페인팅은 소프트웨어 래스터라이저(rasterizers)에서 완료됩니다. 여러분의 앱에서 엘리먼트가 어떻게 레이어들로 그룹지어지는가에 따라 변경된 하나의 엘리먼트 주변의 다른 엘리먼트들 역시 다시 그려져야 할 것입니다.

레이어의 개념이 생소하다면 Tom Wiltzius의 관련 소개를 읽어보시기 바랍니다.

페인트를 발생하는 많은 속성들이 있지만 가장 많이 사용되는 것들은 다음과 같습니다.

페인팅에 영향을 주는 스타일들

colorborder-style
visibilitybackground
text-decorationbackground-image
background-positionbackground-repeat
outline-coloroutline
outline-styleborder-radius
outline-widthbox-shadow
background-size

Source: http://goo.gl/lPVJY6

위에 나열된 속성을 애니메이션하게 되면 그 엘리먼트(들)은 다시 그려져야 할 것이고 그들이 속한 레이어들은 GPU로 업로드되어야 합니다. 모바일 디바이스들은 CPU가 데스크탑의 그것들에 비해 명백히 낮은 성능을 가지고 있기 때문에 특히 고비용이라고 할 수 있으며 이는 페인팅 작업이 더 많은 시간을 요구한다는 것을 뜻합니다. 그리고 CPU와 GPU 간의 대역폭이 제한되어 있으므로 텍스쳐의 전송에는 많은 시간이 소모됩니다.

합성(Composite) 애니메이션 속성들

그러나 페인팅을 발생할 것이라고 예상하지만 때로는 그렇지 않은 단 하나의 CSS 속성이 있습니다. 바로 opacity(투명도)입니다. opacity의 변경은 GPU에 의해 합성 단계에서 낮은 알파값을 가지는 엘리먼트 텍스쳐의 단순한 페인팅으로 처리됩니다. 그러나 그렇게 동작하기 위해서 엘리먼트는 레이어 안에서 유일해야 합니다.

블링크와 웹킷 브라우저에서 opacity에 대한 CSS 트랜지션이나 애니메이션을 가진 엘리먼트는 새로운 레이어를 생성하지만 많은 개발자들이 translateZ(0)translate3d(0,0,0)를 이용하여 수동으로 레이어를 생성하도록 강제하고 있습니다. 레이어를 강제로 생성하는 것은 레이어의 페인팅과 곧 애니메이션이 시작하는 것처럼 준비 상태(read-to-go)로 만들게 되며 (레이어의 생성과 페인팅은 사소한 작업이 아닐뿐더러 애니메이션의 실행을 딜레이시킬 수 있습니다.) 안티알리아싱의 변경들로 인한 즉각적인 외관 변화가 없도록 강제하게 됩니다. 레이어를 추가하는 것은 지양하여야 하지만 여러분은 그러한 작업을 과도하게 할 수도 있으며 과도한 레이어로 인한 멈춤 현상을 읽어보시기 바랍니다.

크롬에서 루트가 아니고 특히 불투명한 레이어는 안티알리아싱 방법이 갑작스럽게 변할 경우, 서브픽셀 안티알리아싱보다는 그레이스케일 안티알리아싱(이 기능은 매우 주목할만한 합니다.)을 사용합니다. 만약 엘리먼트를 애니메이션 시작까지 기다리게 하지 않을 것이라면 빨리 처리하시기 바랍니다.

엘리먼트의 트랜스폼 변경은 위치, 회전, 스케일의 변경이 핵심입니다. 가끔 lefttop 속성을 설정하여 애니메이션을 처리하는 것을 볼 수 있습니다. 위에서 살펴본 바와 같이 문제는 lefttop 모두가 레이아웃 동작을 발생하며 그 동작이 매우 비싸다는 것이 문제입니다. 더 좋은 해결방법은 레이아웃 동작을 일으키지 않는 translate를 엘리먼트에 적용하는 것입니다.

크롬 카나리(Canary)와 사파리에서 필터 또한 애니메이션의 대상입니다. 메인 스레드에서 관리하는 것을 포기하게 하여 가속되고 일반적으로 매우 잘 동작합니다. 그러나 필터들은 인터넷 익스플로러나 파이어폭스에서는 아직 지원되지 않으므로 주의하여 사용해야 합니다.

명령형(Imperative) 대 선언형(Declarative) 애니메이션

개발자들은 종종 애니메이션 방법으로 JavaScript(명령형)과 CSS(선언형) 중에 하나를 결정해야할 때가 있습니다. 각각 장단점이 있으므로 다음과 같이 살펴보도록 하겠습니다.

명령형(Imperative)

명령형 애니메이션의 주요 장점은 주요 단점과 같습니다. 브라우저의 메인 스레드에 위치하는 자바스크립트로 동작한다는 점입니다. 메인 스레드는 다른 자바스크립트, 스타일 계산, 레이아웃, 페인팅으로 이미 바쁜 상태입니다. 그곳에는 종종 스레드 경쟁이 일어납니다. 이것은 여러분이 최종적으로 원하는 애니메이션의 프레임율을 떨어뜨리는 경우를 상당히 증가시킵니다.

자바스크립트를 이용한 애니메이션은 여러분이 매우 다양한 컨트롤을 가능하게 합니다. 시작, 멈춤, 역전환, 인터럽트, 취소 등은 사소한 부분입니다. 패럴랙스(parallax) 스크롤과 같은 몇몇 효과들은 자바스크립트에 의해서만 만들 수 있습니다.

선언형(Declarative)

대체 가능한 접근 방법으로 전환(Transition)과 애니메이션을 CSS에 작성하는 것이 있습니다. 가장 큰 이점은 브라우저가 애니메이션을 최적화할 수 있다는 점입니다. 필요하다면 레이어를 생성할 수도 있고, 몇가지 실행 동작을 여러분이 본 바와 같이 메인 스레드로부터 분리할 수도 있는 것은 좋은 일입니다. 다양한 CSS 애니메이션의 단점 중에 가장 큰 것은 자바스크립트 애니메이션과 같은 강력한 표현력이 부족하다는 것입니다. 의미 있는 방법으로 애니메이션을 결합하는 것은 매우 어려우며, 이것은 작성된 애니메이션이 복잡하고 에러가 나기 쉽다는 것을 뜻합니다.

미래를 예상해봅시다.

웹 표준의 혁신처럼 애니메이션을 둘러싼 몇가지 제한점들은 사라질 것입니다. 구글의 Ian Vollick이 제안한 Worker를 통한 자바스크립트 애니메이션(JavaScript animations via workers)은 스타일의 재계산이나 레이아웃 동작을 발생하지 않는 애니메이션을 제공합니다.

이와 비슷하게 CSS 애니메이션에 대해 웹 애니메이션(Web Animations) 규격이나 Jake Archibald의 확장성에 대한 글과 같은 흥미로운 선언형 접근이 몇가지 더 있습니다.

결론

애니메이션을 잘하는 것은 훌륭한 웹 구축의 핵심입니다. 여러분은 고비용이며 애니메이션의 프레임율을 떨어뜨리는 레이아웃이나 페인트 동작을 발생하는 속성에 대한 애니메이션을 피해야 합니다. 선언형 애니메이션은 명령형에 비해 브라우저가 빠른 시간 안에 최적화할 수 있는 기회를 가지게 되기 때문에 선호할만 합니다.

오늘 날의 트랜스폼들은 GPU가 무거운 작업을 대신 지원해주기 때문에 애니메이션을 위한 최고의 속성들이므로 이것들로 한정해 애니메이션을 할 수 있다면 그렇게 하도록 하시기 바랍니다.

  • opacity
  • translate
  • rotate
  • scale

미래에는 여러분이 자바스크립트를 통해 메인 스레드 비용의 소모가 없는 애니메이션을 하거나 다른 제약이 없는 최적화된 CSS 애니메이션을 통해 비단결처럼 부드러운 애니메이션을 구축할 수 있도록 하는 새로운 방법이 있을 것입니다.

리소스

Comments

0