크로미움 84의 웹 애니메이션 API 개선 사항


원문 : https://web.dev/web-animations/

프라미스로 애니메이션을 조작할 수있고, 교체가능한 애니메이션으로 성능이 개선되었으며, 합성 모드를 사용하여 부드러운 애니메이션을 제공한다.


애니메이션을 잘 사용하면 사용자에게 좋은 브랜드 이미지를 줄 수 있음과 동시에 애플리케이션이 의도한 사용자 액션을 가이드하거나, 기능 사용을 도울 수 있다.

웹 애니메이션 API를 사용하면 개발자가 자바스크립트 명령어로 애니메이션을 작성할 수 있다. 시간에 따라 합성되는 기존 이펙트뿐 아니라 CSS 애니메이션과 트랜지션 그리고 새로 구현된 이펙트를 보다 견고히 할 수 있도록 개발되었다.

원래 크로미움 36에서 출시된 기능으로 오래된 역사를 가지고 있지만, 크로미움 84에서는 이전에 지원되지 않았던 많은 기능을 제공한다.

웹 애니메이션 API의 오래된 역사 웹 애니메이션 API의 오래된 역사

시작하기

@keyframe규칙을 사용한 경우, 웹 애니메이션 API를 통해 애니메이션을 생성해주는 것은 매우 친숙하게 느껴질 것이다. 먼저, 키프레임 오브젝트를 작성해보자.

  • CSS로 작성했을 때

    @keyframes openAnimation {
    0% {
    transform: scale(0);
    }
    100% {
    transform: scale(1);
    }
    }
  • 자바스크립트로 작성했을 때

    const openAnimation = [
    { transform: 'scale(0)' },
    { transform: 'scale(1)' },
    ];
  • CSS에서 애니메이션에 매개변수를 설정해 줄 수 있다.

    .modal {
    animation: openAnimation 1s 1 ease-in;
    }
  • JS로 작성하여 설정해줄 수 있다.

    document.querySelector('.modal').animate(
    openAnimation, {
      duration: 1000, // 1s
      iterations: 1, // single iteration
      easing: 'ease-in' // easing function
    }
    );

코드의 양은 비슷해 보이지만, 자바스크립트로 작성한다면 CSS만 사용했을 때는 갖지 못하는 두 가지 강력한 힘를 얻게 된다. 효과의 순서를 조작할 수 있는 기능과 애니메이션 재생 상태를 제어할 수 있는 기능이 포함되었다.


★ 키프레임을 사용할 때 하이픈이 포함된 속성명은 낙타표기법으로 작성한다. (예를 들면 `background-color`는 `backgroundColor`가 된다.)

element.animate()를 넘어서

업데이트된 웹 애니메이션 API는 더이상 element.animate()를 통해 생성된 애니메이션을 제한하지 않는다. CSS 애니메이션과 트랜지션도 조작할 수 있다.

getAnimations()는 애니메이션을 element.animation() 이용해 만들던지, CSS 애니메이션과 트랜지션과 같은 CSS 규칙을 통해 만들던지 상관없이 요소에 걸려있는 모든 애니메이션을 반환하는 메소드이다. 여기 예제가 있다.

먼저 어디에서 트랜지션 해야 하는지 결정하기 위한 트랜지션의 키프레임을 "얻어"와야 한다. 그런 다음, 크로스 페이드 효과를 내주기 위해 두 개의 새로운 투명도를 조절하는 애니메이션을 추가한다. 크로스 페이드가 완료되면 복사본을 삭제한다.

프라미스로 애니메이션 조작하기

크로미움 84에서, 프라미스로 사용할 수 있는 두 개의 메소드 animation.readyanimation.finished를 지원한다.

  • animation.ready는 보류 중인 변경 사항이 적용될 때 까지 대기할 수 있다. (즉, 재생과 일시 정지 메서드와 같이 재생 관련 흐름 제어)
  • animation.finished는 애니메이션이 완료될 때 사용자가 정의한 자바스크립트 코드를 실행할 수 있는 방법을 제공한다.

예제를 이어서 살펴보자. animation.finished로 구성된 애니메이션 체인을 만들어보자. 수직 변환(scaleY)이 나타나고, 그다음 수평 변환(scaleX)이 이루어지고, 그다음 자식 요소의 불투명도가 변경된다.

모달 요소가 열리면서 변환 및 불투명도 적용된 코드펜 데모 확인

const transformAnimation = modal.animate(openModal, openModalSettings);
transformAnimation.finished.then(() => { text.animate(fadeIn, fadeInSettings)});

다음 애니메이션 셋을 실행하기에 앞서 animation.finished.then()을 사용하여 애니메이션을 연결했다. 이렇게 하면 애니메이션의 실행 순서를 알 수 있고, 속도 조절과 ease 효과와 같은 다른 옵션을 사용하는 다른 요소에도 효과를 적용할 수 있다.

CSS 내에서는, 특히 다중 요소에 연속적으로 정의된 고유한 애니메이션은 재생성하기가 번거로울 수 있다. @keyframe을 사용하고, 애니메이션을 나열하기 위해 정확한 시간을 계산하고, 애니메이션이 차례로 발생하기 전에 animation-delay를 사용하자.

예: 애니메이션 재생, 일시 정지 및 효과 되감기

열 수 있는 것은 닫아야 한다! 다행히, 크로미움 39부터 웹 애니메이션 API는 애니메이션의 재생, 일시 정지 및 되감기 기능을 제공한다.

위에 애니메이션 에제를 가져와 .reverse()를 사용하여 버튼을 클릭했을 때 부드럽게 반전된 애니메이션 효과를 줄 수 있다. 이러한 방식으로 모달에 좀 더 부드럽고 상황에 맞는 상호작용을 만들 수 있다.

버튼을 클릭하여 모달을 열고 닫는 예제. 데모 보기

두 개의 보류 중인 재생 애니메이션(openModal과 인라인 불투명도 변환 애니메이션)을 만든 다음, 애니메이션 중 하나를 일시 정지하고 다른 애니메이션이 완료될 때까지 지연시킨다. 그러면 재생하기 전에 각각의 애니메이션이 완료될 때까지 대기할 수 있는 프라미스를 사용할 수 있다. 마지막으로, 플래그가 설정되어 있는지 확인한 후 각 애니메이션 효과를 반전시킬 수 있다.

예: 부분 키프레임을 사용한 동적 상호작용

마우스를 클릭하면 애니메이션이 새 위치로 조정되어 대상이 변경되는 예제 데모 확인

selector.animate([{transform: `translate(${x}px, ${y}px)`}],
    {duration: 1000, fill: 'forwards'});

이 예제에서는 키프레임은 하나만 사용되었으며 시작 위치는 지정되어 있지 않다. 부분 키프레임을 사용한 예제이다. 여기서 마우스 핸들러는 몇 가지 작업을 수행하는데, 새로운 종료 위치를 설정하고 새로운 애니메이션을 발생시킨다. 새로운 시작 위치는 현재 위치를 기준으로 계산한다.

기존 트랜지션이 실행되는 동안 새로운 트랜지션이 발생될 수 있다. 즉, 현재 트랜지션이 중단되고 새로운 트랜지션이 만들어진 것이다.

교체가능한 애니메이션으로 성능 개선

mousemove와 같은 이벤트를 기반으로 애니메이션을 만들면, 매 시간마다 새로운 애니메이션이 생성되므로 메모리를 빨리 소모하고 성능을 저하시킬 수 있다. 이러한 문제를 해결하기 위해 크로미움 83에서는 교체가능한 애니메이션이 도입되어 자동적으로 정리가 가능해졌다. 완료된 애니메이션은 교체가능한 것으로 플래그가 지정되며 다른 완료된 애니메이션으로 교체했을 경우 자동으로 제거된다. 다음 에제를 살펴보자.

마우스가 움직이면 혜성의 꼬리가 쫒아오는 애니메이션. 데모 보기

elem.addEventListener('mousemove', evt => {
 rectangle.animate(
   { transform: translate(${evt.clientX}px, ${evt.clientY}px) },
   { duration: 500, fill: 'forwards' }
 );
});

마우스가 움직일 때마다 브라우저는 혜성의 꼬리에 있는 각 공의 위치를 다시 계산하여 새로운 지점에 대한 애니메이션을 만든다. 이제 브라우저는 아래 내용의 경우에 교체가능한 이전 애니메이션을 제거할 수 있다.

  1. 애니메이션이 끝났을 때
  2. 완료된 합성 순서가 높은 애니메이션이 하나 이상 있을 때
  3. 새로운 애니메이션이 이전과 같은 속성을 애니메이션 할 때

anim.onremove를 사용하여 이벤트 핸들러에서 제거된 애니메이션 수를 집계하여 교체된 애니메이션의 갯수를 정확히 알 수있다.

애니메이션을 제어할 수 있는 몇 가지 추가 메소드가 있다.

  • animation.replaceState()는 애니메이션의 활성 상태, 지속 및 제거 여부를 추적할 수 있는 수단을 제공한다.
  • animation.commitStyles()은 합성 순서에서 요소의 모든 애니메이션을 포함하여 기본 스타일을 바탕으로 요소의 스타일을 갱신한다.
  • animation.persist()는 교체 불가능한 애니메이션으로 표시한다.

★ `animation.commitStyles()`와 `animation.persist()`는 일반적으로 "add"와 같은 합성 모드와 함께 사용된다. 아래에 합성 모드에 대한 데모를 보면서 어떻게 사용되는지 살펴보자.

합성 모드를 통한 부드러운 애니메이션

이제 웹 애니메이션 API를 사용하여 애니메이션의 합성 모드를 설정할 수 있다. 즉, 기본 모드인 "replace"외에도 증가와 누적될 수 있다. 합성 모드를 사용하면, 개발자들이 구별된 애니메이션을 작성하고 애니메이션 효과가 결합되는 방식을 제어할 수 있다. 세 가지 합성 모드 replace(기본 모드), addaccumlate를 지원한다.

애니메이션을 합성하면 개발자는 간결하고 구별된 효과를 작성할 수 있으며, 결합된 효과를 볼 수 있다. 아래 예제에서는 각 네모에 회전(rotation)과 크기 조절(scale) 키프레임을 적용하였고, 옵션을 추가하여 합성 모드만 각각 다르게 설정해주었다.

기본, 추가, 누적 합성 모드를 보여주는 데모. 데보 보기

기본 모드인 'replace' 합성 모드에서는 최종 애니메이션을 변환 속성을 교체하고 rotate(360deg) scale(1.4)로 끝난다. 'add' 합성은 회전 값을 더하고 크기 조절 값을 곱한다. 최종 상태의 결괏값은 rotate(720deg) scale(1.96)이다. 'accumulate'는 변환을 결합하여 결괏값이 rotate(720deg) scale(1.8)이 된다. 이러한 합성 모드의 복잡한 내용에 대해 자세히 알고 싶다면 웹 애니메이션 스펙 문서의 CompositeOperation과 CompositeOperationOrAuto을 확인해보자.

UI 요소 예제를 살펴보자.

두 개의 합성 애니메이션이 적용되어 튕김 효과를 가지는 드롭다운 메뉴. 데모 보기

여기서는, 두개의 top애니메이션이 합성된다. 첫번째는 매크로 애니메이션으로 페이지 상단에서 슬아이드-인 효과로 메뉴의 전체 높이에 따라 드롭다운을 이동시키고, 두번째는 마이크로 애니메이션으로 하단에 부딪히면서 약간 튕겨나가는 효과가 적용되었다. 'add'합성 모드를 사용하면 더 부드러운 트랜지션이 가능하다.

const dropDown = menu.animate(
    [
      { top: `${-menuHeight}px`, easing: 'ease-in' },
      { top: 0 }
    ], { duration: 300, fill: 'forwards' });

  dropDown.finished.then(() => {
    const bounce = menu.animate(
      [
        { top: '0px', easing: 'ease-in' },
        { top: '10px', easing: 'ease-out' },
        { ... }
      ], { duration: 300, composite: 'add' });
  });

웹 애니메이션 API의 다음 기능

최신 브라우저에서 애니메이션 기능에 대한 흥미로운 결과물이며, 더 많은 기능이 파이프 라인에 추가되고있다. 앞으로 추가될 기능의 정보는 아래의 명세들로 확인할 수 있다.


조정은, FE Development Lab2020.06.02Back to list