Animacje internetowe – element element.animate() jest teraz w Chrome 36

Brendan Kenny
Brendan Kenny

Animacje w internecie były kiedyś domeną JavaScriptu, ale wraz z rozwojem urządzeń mobilnych przeniesiono je do CSS ze względu na deklaratywną składnię i możliwości optymalizacji, jakie oferuje ten język. Ponieważ 60 FPS na urządzeniach mobilnych to zawsze cel, warto nigdy nie wychodzić poza to, co przeglądarki potrafią skutecznie wyświetlać.

Pojawia się coraz więcej narzędzi, które zwiększają wydajność animacji opartych na JavaScript, ale świętym Graalem jest ujednolicenie deklaratywnych i imperatywnych animacji, w których przypadku decyzja o sposobie tworzenia animacji jest podejmowana na podstawie tego, co jest najczystszym kodem, a nie tego, co jest możliwe w jednym przypadku, a co w drugim.

Animacje internetowe mogą sprostać temu wyzwaniu. Pierwsza część tej funkcji została wprowadzona w Chrome 36 w postaci element.animate(). Ta nowa funkcja umożliwia tworzenie animacji wyłącznie w JavaScript i wykonywanie jej tak samo wydajnie jak animacji lub przejść CSS (w fakcie od wersji 34 Chrome wszystkie te metody są obsługiwane przez ten sam mechanizm animacji internetowych).

Składnia jest prosta, a jej części powinny być Ci znane, jeśli kiedykolwiek pisałeś/pisałaś animację lub przejście CSS:

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

Największą zaletą tej nowej funkcji jest wyeliminowanie wielu skomplikowanych kroków, które trzeba było wykonać, aby uzyskać płynną animację bez zacięć.

Na przykład w zeszłym roku w ramach śledzenia Świętego Mikołaja chcieliśmy, aby śnieg padał bez przerwy. Zdecydowaliśmy się na animację za pomocą CSS, aby zrobić to efektywnie.

Chcieliśmy jednak dynamicznie wybierać położenie poziome śniegu na podstawie ekranu i zdarzeń występujących w samej scenie. Oczywiście wysokość śniegu (wysokość okna przeglądarki użytkownika) nie była znana, dopóki nie uruchomiliśmy animacji. Oznaczało to, że musieliśmy użyć przejść CSS, ponieważ tworzenie animacji CSS w czasie wykonywania szybko staje się skomplikowane (a setki płatków śniegu oznaczają setki nowych reguł stylizacji).

Dlatego zastosowaliśmy następujące podejście, które powinno być Ci znane:

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

Kluczem jest komentarz „wait a frame”. Aby rozpocząć przejście, przeglądarka musi potwierdzić, że element znajduje się w pozycji początkowej. Możesz to zrobić na kilka sposobów. Jednym z najczęstszych sposobów jest odczytywanie z jednej z właściwości elementu, która zmusza przeglądarkę do obliczenia układu, dzięki czemu wie ona, że element ma pozycję początkową przed przejściem do pozycji końcowej. Dzięki tej metodzie możesz pochwalić się swoją wiedzą na temat wewnętrznej budowy przeglądarki, ale nadal będziesz czuć się źle z każdą wciśniętą klawiaturą.

Natomiast odpowiednia funkcja element.animate() jest bardzo jasna i dokładnie określa, co ma się stać:

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

Dostępnych jest wiele innych opcji. Podobnie jak w przypadku animacji CSS, animacje internetowe mogą być opóźniane i powtarzane:

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

AnimationPlayer

Funkcja element.animate() zwraca obiekt AnimationPlayer, który będzie coraz ważniejszy wraz z wprowadzaniem kolejnych specyfikacji animacji internetowych. Zarówno animacje utworzone za pomocą JavaScript, jak i CSS będą miały powiązane odtwarzacze animacji, co pozwoli na ich płynne łączenie w przydatne i ciekawe sposoby.

Obecnie AnimationPlayer ma tylko 2 funkcje, ale obie są bardzo przydatne. Animację możesz anulować w dowolnym momencie, używając 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();

Na szczęście wszystkich, którzy próbowali już w przeszłości tworzyć system animacji na podstawie animacji lub przejść CSS, animacje webowe zawsze wywołują zdarzenie po zakończeniu działania:

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

Wypróbuj

Wszystkie te funkcje są dostępne w Chrome 36, który dziś przechodzi do wersji beta. Jeśli chcesz to wypróbować, użyj natywnej implementacji w Chrome 36. Dostępny jest jednak polyfill Web Animations, który udostępnia znacznie większą część pełnej specyfikacji Web Animations w dowolnej nowoczesnej przeglądarce evergreen.

Demo efektu śniegu jest dostępne do wypróbowania zarówno w wersji natywnej element.animate(), jak i w wersji polyfill.

Powiedz nam, co myślisz

To wstępna wersja tego, co jest w planach, i jest udostępniana, abyśmy mogli od razu uzyskać opinie programistów. Nie mamy jeszcze pewności, czy uwzględniliśmy wszystkie przypadki użycia ani czy wygładzimy wszystkie ostre krawędzie obecnych interfejsów API dotyczących animacji. Jedynym sposobem, abyśmy mogli się tego dowiedzieć i dobrze to zrobić, jest wypróbowanie przez deweloperów i przekazanie nam opinii.

Komentarze do tego posta są oczywiście cenne, a komentarze dotyczące samego standardu można przesłać do grup roboczych CSS i SVG za pomocą listy mailingowej public-fx.

Aktualizacja z października 2014 r.: w Chrome 39 dodano obsługę kilku dodatkowych metod związanych z sterowaniem odtwarzaniem, takich jak play(), pause()reverse(). Umożliwia też przeskakiwanie do określonego punktu na osi czasu animacji za pomocą właściwości currentTime. Jak działa ta funkcja, możesz zobaczyć w tym nowym filmie demonstracyjnym.

Dziękujemy Addie Osmani i Maxowi Heinritzowi za pomoc w przygotowaniu tego posta.