Animazioni web: element.animate() è ora disponibile in Chrome 36

Brendan Kenny
Brendan Kenny

Un tempo le animazioni sul web erano appannaggio di JavaScript, ma con il passaggio al mobile, le animazioni sono passate al CSS per la sintassi dichiarativa e le ottimizzazioni che i browser erano in grado di apportare. Dato che il tuo obiettivo è sempre 60 fps sui dispositivi mobili, ha senso non andare oltre ciò che i browser sanno mostrare in modo efficiente.

Esistono sempre più strumenti per rendere più efficienti le animazioni basate su JavaScript, ma l'obiettivo finale è unificare le animazioni dichiarative e imperative , in cui la decisione su come scrivere le animazioni si basa sul codice più chiaro, non su ciò che è possibile in una forma e non nell'altra.

Web Animations è la risposta a questa esigenza e la prima parte è stata implementata in Chrome 36 sotto forma di element.animate(). Questa nuova funzione ti consente di creare un'animazione esclusivamente in JavaScript e di eseguirla in modo efficiente come qualsiasi animazione o transizione CSS (infatti, a partire da Chrome 34, lo stesso motore di animazioni web gestisce tutti questi metodi).

La sintassi è semplice e le sue parti dovrebbero essere familiari se hai mai scritto una transizione o un'animazione CSS:

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

Il più grande vantaggio di questa nuova funzionalità è l'eliminazione di una serie di passaggi complicati che in precedenza dovevamo seguire per ottenere un'animazione fluida e senza scatti.

Ad esempio, per il Santa Tracker dello scorso anno, volevamo che la neve cadesse continuamente e abbiamo deciso di animarla tramite CSS in modo da poterla realizzare in modo efficiente.

Tuttavia, volevamo scegliere la posizione orizzontale della neve in modo dinamico in base allo schermo e agli eventi che si verificano nella scena stessa e, naturalmente, l'altezza della caduta della neve (l'altezza della finestra del browser dell'utente) non sarebbe stata nota fino a quando non avremmo iniziato a eseguire il servizio. Ciò significava che dovevamo davvero utilizzare le transizioni CSS, poiché la creazione di un'animazione CSS in fase di esecuzione diventa rapidamente complessa (e centinaia di fiocchi di neve significano centinaia di nuove regole di stile).

Abbiamo quindi adottato il seguente approccio, che dovrebbe essere familiare:

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

La chiave è nel commento "attendi un frame". Per avviare correttamente una transizione, il browser deve confermare che l'elemento si trova nella posizione iniziale. Esistono diversi modi per farlo. Uno dei modi più comuni è leggere da una delle proprietà dell'elemento che forza il browser a calcolare il layout, assicurandosi così che sappia che l'elemento ha una posizione iniziale prima di passare alla posizione finale. L'utilizzo di questo metodo ti consente di congratularti con te stesso per la tua conoscenza superiore delle parti interne del browser, pur sentendoti sporco a ogni battitura.

Al contrario, la chiamata element.animate() equivalente non potrebbe essere più chiara, poiché indica esattamente ciò che è previsto:

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

Esistono molte altre opzioni. Come per le relative controparti CSS, le animazioni web possono essere ritardate e iterate:

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

AnimationPlayer

element.animate() restituisce in realtà un oggetto AnimationPlayer, che diventerà sempre più importante con il lancio di ulteriori specifiche sulle animazioni web. Sia le animazioni create con JavaScript sia quelle create con CSS avranno AnimationPlayer associati, il che consente di combinarle facilmente in modi utili e interessanti.

Per il momento, però, AnimationPlayer ha solo due funzionalità, entrambe molto utili. Puoi annullare un'animazione in qualsiasi momento utilizzando 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();

E, per la gioia di tutti coloro che in passato hanno tentato di creare un sistema di animazione basato su animazioni o transizioni CSS, le animazioni web attivano sempre un evento al termine:

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

Prova

Tutte queste funzionalità sono disponibili in Chrome 36 e passeranno alla versione beta oggi stesso. Se vuoi provarlo, prova a utilizzare l'implementazione nativa in Chrome 36. Tuttavia, esiste un polyfill di Web Animations, che offre una parte molto più ampia della specifica completa di Web Animations a qualsiasi browser moderno e evergreen.

È disponibile una demo dell'effetto neve che puoi provare utilizzando sia la versione nativa di element.animate() sia il polyfill.

Facci sapere la tua opinione

In realtà, si tratta di un'anteprima di ciò che verrà rilasciato in futuro ed è stata pubblicata appositamente per ricevere subito il feedback degli sviluppatori. Non sappiamo ancora se abbiamo raggiunto tutti i casi d'uso o se abbiamo eliminato tutti i problemi delle API attuali per l'animazione. L'unico modo per noi di saperlo e di fare le cose per bene è che gli sviluppatori la provino e ci facciano sapere cosa ne pensano.

I commenti su questo post sono ovviamente importanti e i commenti sullo standard stesso possono essere inviati ai gruppi di lavoro CSS e SVG tramite la mailing list public-fx.

Aggiornamento di ottobre 2014: Chrome 39 aggiunge il supporto di diversi metodi aggiuntivi relativi al controllo della riproduzione, come play(), pause() e reverse(). Supporta anche il passaggio a un punto specifico della sequenza temporale di un'animazione tramite la proprietà currentTime. Puoi vedere questa funzionalità in azione in questa nuova demo.

Grazie ad Addy Osmani e Max Heinritz per l'aiuto fornito per la stesura di questo post.