웹 애니메이션 - 이제 Chrome 36에서element.animate()가 제공됩니다.

Brendan Kenny
Brendan Kenny

웹의 애니메이션은 한때 JavaScript의 영역이었지만 모바일로 전환되면서 선언적 문법과 브라우저에서 이를 통해 실행할 수 있는 최적화를 위해 CSS로 전환되었습니다. 모바일에서 항상 60fps를 목표로 삼는 경우 브라우저가 효율적으로 표시하는 방법을 벗어나지 않는 것이 좋습니다.

JavaScript 기반 애니메이션을 더 효율적으로 만드는 도구가 점점 늘어나고 있지만, 궁극적인 목표는 선언적 애니메이션과 명령형 애니메이션을 통합하는 것입니다. 애니메이션을 작성하는 방법을 결정할 때는 한 형식에서는 가능하고 다른 형식에서는 불가능한 것이 아니라 가장 명확한 코드를 기준으로 결정해야 합니다.

Web Animations이 이 요구사항에 대답할 수 있으며, 그 중 첫 번째 부분은 element.animate() 형식으로 Chrome 36에 포함되었습니다. 이 새 함수를 사용하면 JavaScript로만 애니메이션을 만들고 CSS 애니메이션이나 전환만큼 효율적으로 실행할 수 있습니다. 실제로 Chrome 34부터 이러한 모든 메서드는 정확히 동일한 웹 애니메이션 엔진에서 실행됩니다.

문법은 간단하며 CSS 전환이나 애니메이션을 작성해 본 적이 있다면 그 부분이 익숙할 것입니다.

element.animate([
    {cssProperty: value0},
    {cssProperty: value1},
    {cssProperty: value2},
    //...
], {
    duration: timeInMs,
    iterations: iterationCount,
    delay: delayValue
});

이 새로운 함수의 가장 큰 장점은 이전에 원활하고 끊김 없는 애니메이션을 얻기 위해 거쳐야 했던 많은 불편한 절차가 사라졌다는 점입니다.

예를 들어 작년 산타 추적기에서는 눈이 계속 내리는 모습을 표현하고자 했으며, 효율적으로 이를 구현할 수 있도록 CSS를 통해 애니메이션을 적용하기로 했습니다.

하지만 장면 자체에서 진행되는 화면과 이벤트를 기반으로 눈의 가로 위치를 동적으로 선택하고 싶었습니다. 물론 눈이 내리는 높이 (사용자의 브라우저 창 높이)는 실제로 실행될 때까지 알 수 없습니다. 즉, 런타임에 CSS 애니메이션을 작성하는 작업이 빠르게 복잡해지므로 CSS 전환을 사용해야 했습니다. 수백 개의 눈송이는 수백 개의 새로운 스타일 지정 규칙을 의미합니다.

따라서 익숙한 다음 접근 방식을 취했습니다.

snowFlake.style.transform = 'translate(' + snowLeft + 'px, -100%)';
// wait a frame
snowFlake.offsetWidth;
snowFlake.style.transitionProperty = 'transform';
snowFlake.style.transitionDuration = '1500ms';
snowFlake.style.transform = 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)';

'프레임 대기' 주석에 키가 있습니다. 전환을 성공적으로 시작하려면 브라우저가 요소가 시작 위치에 있음을 인식해야 합니다. 방법은 다음과 같습니다. 가장 일반적인 방법 중 하나는 브라우저가 레이아웃을 계산하도록 강제하는 요소 속성 중 하나를 읽어서 요소에 시작 위치가 있음을 알 수 있도록 하는 것입니다. 그러면 요소가 끝 위치로 전환되기 전에 시작 위치를 알 수 있습니다. 이 방법을 사용하면 브라우저 내부 구조에 대한 우수한 지식을 뽐내면서도 매번 키를 누를 때마다 불쾌감을 느낄 수 있습니다.

반면 이에 상응하는 element.animate() 호출은 의도를 정확하게 전달하여 더 명확할 수 없습니다.

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);

그 외에도 다양한 옵션이 있습니다. CSS 애니메이션과 마찬가지로 Web Animations도 지연되고 반복될 수 있습니다.

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], {
    duration: 1500,
    iterations: 10,
    delay: 300
});

AnimationPlayer

element.animate()는 실제로 AnimationPlayer 객체를 반환하며, 이는 웹 애니메이션 사양이 더 많이 출시될수록 점점 더 중요해질 것입니다. JavaScript와 CSS로 만든 애니메이션 모두 연결된 AnimationPlayer가 있으므로 유용하고 흥미로운 방식으로 원활하게 결합할 수 있습니다.

하지만 현재 AnimationPlayer에는 두 가지 유용한 기능만 있습니다. AnimationPlayer.cancel()를 사용하여 언제든지 애니메이션을 취소할 수 있습니다.

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
// less than 1500ms later...changed my mind
player.cancel();

또한 이전에 CSS 애니메이션 또는 전환을 중심으로 애니메이션 시스템을 빌드하려고 시도한 모든 사용자에게 다행스러운 소식은 웹 애니메이션이 완료되면 항상 이벤트가 실행된다는 것입니다.

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
player.onfinish = function(e) {
    console.log('per aspera ad terra!');
}

사용해 보기

이 기능은 모두 Chrome 36에서 제공되며 오늘 베타로 전환됩니다. 사용해 보려면 Chrome 36의 네이티브 구현을 사용해 보세요. 하지만 Web Animations polyfill이 있어 최신 상시 지원 브라우저에 전체 Web Animations 사양의 상당히 큰 부분을 제공합니다.

눈 효과 데모를 통해 element.animate()네이티브 버전과 폴리필을 모두 사용해 볼 수 있습니다.

여러분의 의견을 공유해 주세요

하지만 이 버전은 향후 출시될 기능을 미리 살펴보고 개발자의 의견을 즉시 수렴하기 위해 출시된 버전입니다. 아직 모든 사용 사례를 충족했는지 또는 애니메이션을 위한 현재 API의 모든 거친 부분을 다듬었는지 확실하지 않습니다. 개발자가 직접 사용해 보고 의견을 알려주셔야만 Google에서 이 기능을 제대로 이해하고 개선할 수 있습니다.

이 게시물에 대한 의견은 물론 소중하며 표준 자체에 대한 의견은 public-fx 메일링 리스트를 통해 CSS 및 SVG 작업 그룹에 전달할 수 있습니다.

2014년 10월 업데이트: Chrome 39에서는 재생 제어와 관련된 여러 추가 메서드(예: play(), pause(), reverse())에 대한 지원을 추가합니다. 또한 currentTime 속성을 통해 애니메이션 타임라인의 특정 지점으로 이동하는 기능도 지원합니다. 이 새로운 데모에서 이 기능을 작동하는 모습을 확인할 수 있습니다.

이 게시물 작성에 도움을 주신 Addy Osmani와 Max Heinritz님께 감사드립니다.