Ulepszenia interfejsu Web Animations API w Chromium 84

Organizowanie animacji za pomocą obietnic, zwiększenie wydajności dzięki wymiennym animacjam i płynniejsze animacje w trybach złożonych.

Kevin Ellis
Kevin Ellis

Prawidłowo używane animacje poprawiają postrzeganie Twojej marki i zapamiętują ich zapamiętywanie, pomagają użytkownikom w działaniach oraz ułatwiają im poruszanie się po aplikacji, zapewniając kontekst w przestrzeni cyfrowej.

Interfejs Web Animations API to narzędzie, które umożliwia programistom pisanie imperatywnych animacji w języku JavaScript. Został on opracowany, aby wspierać animacje CSS i implementacje przejść oraz umożliwić opracowanie przyszłych efektów, a także skomponowanie i mierzenie czasu istniejących efektów.

Mimo że Firefox i Safari korzystają już ze wszystkich specyfikacji funkcji, Chromium 84 wprowadza do Chrome i Edge wiele nieobsługiwanych wcześniej funkcji, które umożliwiają współdziałanie w różnych przeglądarkach.

Interfejs Web Animations API po raz pierwszy pojawił się w Chromium w wersji 36, lipiec 2014 r. Teraz specyfikacja zostanie ukończona w wersji 84 (od lipca 2020 r.).
Długa historia interfejsu Web Animations API w Chromium.

Wprowadzenie

Tworzenie animacji za pomocą interfejsu Web Animations API powinno wydawać się bardzo znajome, jeśli korzystasz z reguł @keyframe. Najpierw utwórz obiekt klatki kluczowej. W CSS może to wyglądać tak:

@keyframes openAnimation {
  0% {
    transform: scale(0);
  }
  100% {
    transform: scale(1);
  }
}

w kodzie JavaScriptu wyglądałoby to tak:

const openAnimation = [
  { transform: 'scale(0)' },
  { transform: 'scale(1)' },
];

Miejsce, w którym ustawiasz parametry animacji w CSS:

.modal {
  animation: openAnimation 1s 1 ease-in;
}

wpisz w JS:

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

Ilość kodu jest mniej więcej taka sama, ale JavaScript daje dostęp do możliwości, które nie są dostępne w samym kodzie CSS. Obejmuje to możliwość sekwencjonowania efektów i większą kontrolę nad stanami gry.

Powyżej element.animate()

Jednak po aktualizacji interfejs Web Animations API nie jest już ograniczony do animacji utworzonych w element.animate(). Możemy także manipulować animacjami i przejściami CSS.

getAnimations() to metoda, która zwraca wszystkie animacje w elemencie niezależnie od tego, czy został on utworzony za pomocą funkcji element.animate(), czy za pomocą reguł CSS (animacja lub przejście CSS). Oto przykład:

Musisz najpierw "get" klatek kluczowych przejścia, aby określić, od którego miejsca przechodzimy. Następnie tworzysz dwie nowe animacje przezroczystości, które włączają efekt przenikania. Po zakończeniu przenikania usuniesz kopię.

Organizacja animacji za pomocą obietnic

W Chromium 84 dostępne są teraz 2 metody, których można używać z obietnicami: animation.ready i animation.finished.

  • animation.ready umożliwia czekanie, aż oczekujące zmiany zaczną obowiązywać (np. przełączanie się między metodami sterowania odtwarzaniem, jak odtwarzanie i wstrzymywanie odtwarzania).
  • animation.finished umożliwia wykonywanie niestandardowego kodu JavaScript po zakończeniu animacji.

Kontynuujmy nasz przykład i utwórz skoordynowany łańcuch animacji za pomocą funkcji animation.finished. Tutaj znajdziesz przekształcenie pionowe (scaleY), a po nim poziome (scaleX) i zmianę przezroczystości elementu podrzędnego:

Zastosowanie przekształceń i przezroczystości do otwierającego elementu modalnego. Zobacz prezentację na platformie Codepen
const transformAnimation = modal.animate(openModal, openModalSettings);
transformAnimation.finished.then(() => { text.animate(fadeIn, fadeInSettings)});

Połączyliśmy te animacje przy użyciu funkcji animation.finished.then() przed uruchomieniem następnego zestawu animacji w łańcuchu. W ten sposób animacje będą wyświetlać się w odpowiedniej kolejności, a nawet zastosujesz efekty do różnych elementów docelowych o odmiennych opcjach (takich jak szybkość czy łatwość).

W przypadku CSS odtworzenie takiej animacji byłoby kłopotliwe, zwłaszcza w przypadku stosowania unikalnych, ale ułożonych w sposób animacji animacji do wielu elementów. Musisz użyć właściwości @keyframe, ustalić właściwe wartości procentowe czasu, by umieścić animacje, i użyć animation-delay przed uruchomieniem animacji w sekwencji.

Przykład: odtwarzanie, wstrzymywanie i odwracanie

Co można otworzyć, powinno zostać zamknięte! Na szczęście od wersji Chromium 39 interfejs Web Animations API umożliwia nam odtwarzanie, wstrzymywanie i odwracanie animacji.

Możesz wykorzystać powyższą animację i nadać jej płynną, odwróconą animację po ponownym kliknięciu przycisku za pomocą funkcji .reverse(). W ten sposób można zapewnić płynniejszy i bardziej kontekstowe interakcje z naszym interfejsem.

Przykład otwierania i zamykania modalnego po kliknięciu przycisku. Zobacz prezentację Glitch

Możesz tylko utworzyć dwie oczekujące animacje (openModal i przekształcenie nieprzezroczystości wbudowane), a następnie wstrzymać jedną z nich i opóźnić ją do momentu zakończenia drugiej. Następnie możesz korzystać z obietnic czekania na zakończenie każdej z nich, zanim zagrasz. Na koniec możesz sprawdzić, czy flaga jest ustawiona, a potem odwrócić każdą animację.

Przykład: dynamiczne interakcje z częściowymi klatkami kluczowymi

Przykład ponownego kierowania, w którym kliknięcie myszą przenosi animację do nowej lokalizacji. Zobacz prezentację Glitch
selector.animate([{transform: `translate(${x}px, ${y}px)`}],
    {duration: 1000, fill: 'forwards'});

W tym przykładzie mamy tylko jedną klatkę kluczową i nie określono pozycji początkowej. Oto przykład użycia częściowych klatek kluczowych. Moduł obsługi myszy wykonuje tutaj kilka czynności: ustawia nową lokalizację końcową i aktywuje nową animację. Nowa pozycja początkowa jest ustalana na podstawie bieżącej pozycji bazowej.

Nowe operacje przenoszenia mogą być aktywowane, gdy istniejące są nadal wykonywane. Oznacza to, że bieżące przejście zostanie przerwane i zostanie utworzone nowe.

Lepsza wydajność dzięki wymiennym animacji

Podczas tworzenia animacji na podstawie zdarzeń, np. 'mousemove', za każdym razem tworzona jest nowa animacja, co może szybko zajmować pamięć i obniżać wydajność. Aby rozwiązać ten problem, w Chromium 83 wprowadzono animacje wymienne, które umożliwiają automatyczne czyszczenie, w którym zakończone animacje są oznaczane jako możliwe do wymiennego i automatycznie usuwane po zastąpieniu ich inną zakończoną animacją. Na przykład:

Podczas ruchu myszy porusza się ślad komety. Zobacz prezentację Glitch
elem.addEventListener('mousemove', evt => {
  rectangle.animate(
    { transform: translate(${evt.clientX}px, ${evt.clientY}px) },
    { duration: 500, fill: 'forwards' }
  );
});

Za każdym razem, gdy użytkownik porusza się myszą, przeglądarka ponownie oblicza położenie każdej kuli na śladzie komety i tworzy animację przedstawiającą nowy punkt. Przeglądarka wie teraz, że ma usunąć stare animacje (umożliwiając ich zastąpienie), gdy:

  1. Animacja jest zakończona.
  2. Na wyższej pozycji w kolejności złożonych jest co najmniej jedna animacja, która też się zakończyła.
  3. Nowe animacje mają te same właściwości.

Aby zobaczyć, ile animacji jest zastępowanych, odliczaj jeden licznik z każdą usuniętą animacją za pomocą funkcji anim.onremove, aby aktywować licznik.

Istnieje kilka dodatkowych metod, które pozwalają jeszcze bardziej zwiększyć możliwości sterowania animacją:

  • animation.replaceState() udostępnia sposoby śledzenia, czy animacja jest aktywna, nieprzerwana czy usunięta.
  • animation.commitStyles() aktualizuje styl elementu na podstawie stylu bazowego wraz ze wszystkimi animacjami tego elementu w kolejności złożonej.
  • animation.persist() oznacza animację jako niezmienną.

Płynniejsze animacje dzięki trybom komponowanym

Za pomocą interfejsu Web Animations API możesz ustawić tryb złożony animacji, który oprócz domyślnego trybu „zastępuj” może być sumujący lub skumulowany. Tryby złożone umożliwiają programistom pisanie odrębnych animacji i kontrolę nad sposobem łączenia efektów. Obecnie obsługiwane są 3 tryby złożone: 'replace' (tryb domyślny), 'add' i 'accumulate'.

Gdy tworzysz animacje złożone, programista może napisać krótkie, wyraziste efekty i zobaczyć je razem. W przykładzie poniżej do każdego pola stosujemy obracanie i skalowanie klatki kluczowej, przy czym jedyną korektą jest tryb złożony i dodaliśmy opcję:

Demonstracja przedstawiająca domyślne, dodawanie i akumulowanie trybów złożonych. Zobacz prezentację Glitch

W domyślnym trybie złożonym 'replace' końcowa animacja zastępuje właściwość „transform” i kończy się na wartości rotate(360deg) scale(1.4). W przypadku funkcji 'add' funkcja złożony dodaje rotację i mnoży skalę, co daje wynik o wartości rotate(720deg) scale(1.96). Funkcja 'accumulate' łączy przekształcenia, tak aby uzyskać rotate(720deg) scale(1.8). Aby dowiedzieć się więcej o złożoności tych trybów złożonych, zapoznaj się z informacjami o wyliczeniach CompositeOperation i CompositeOperationOrAuto w specyfikacji animacji Web Animations.

Przyjrzyjmy się przykładowi elementu interfejsu:

Menu ruchome, z którym zastosowano 2 skomponowane animacje. Zobacz prezentację Glitch

W tym przykładzie skomponowane są 2 animacje top. Pierwsza to animacja makro, która przesuwa menu o całą wysokość i w efekcie wysuwania się z góry strony. Druga – mikroanimacja – powoduje skażenie menu po dotknięciu go do dołu. Użycie trybu złożonego 'add' umożliwia płynniejsze przejście.

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' });
  });

Co dalej z interfejsem Web Animations API

Są to wszystkie niesamowite dodatki do funkcji animacji w dzisiejszych przeglądarkach, a planujemy ich jeszcze więcej. Zapoznaj się z przyszłymi specyfikacjami, aby dowiedzieć się więcej o nadchodzących zmianach: