L’avvento del CSS3 ha aggiunto la possibilità creare animazioni tramite foglio di stile. Il tutto avviene tramite le parole chiave animation
e keyframes
. Per capire il funzionamento delle animazioni CSS vediamo questo semplice esempio.
.square { width: 100px; height: 100px; background-color: red; } .square.animated { animation: backgroud-color-animation 1s; } @keyframes backgroud-color-animation { from {background-color: red;} to {background-color: yellow;} }
Come vedete tramite la proprietà animation
definiamo il nome dell’animazione e la sua durata. Tramite invece keyframes
definiamo quali sono gli stati di cui l’animazione stessa è composta. In pratica stiamo dicendo che gli elementi marcati con la classe animated
e square
passeranno dall’avere un colore di background rosso ad uno giallo in un secondo.
A volte abbiamo bisogno di pilotare l’avvio di un’animazione, ad esempio dopo che l’utente clicca su un determinato button
. Immaginate ad esempio l’apertura di un menù laterale. In questi casi basta collegare la classe animated
proprio in risposta agli eventi scatenati dall’utente.
Web Animations Api
Questo approccio ha però dei limiti, immaginate ad esempio di voler scatenare una funzione JavaScript al termine dell’animazione. Questa cosa non è facilmente fattibile a meno di hack clamorosi come appoggiarsi a setTimeout
vari ed eventuali. In nostro soccorso ci sono le Web Animations Api, nuova specifica W3C che permette di controllare le nostre animazioni CSS con del semplice codice JavaScript. Come vedremo grazie a questa Api potremmo controllare il flusso di un’animazione e, soprattutto, combinarle in gruppi o sequenze. Il tutto senza perdere l’espressività semantica data dal CSS3.
Can I use it?
Sbirciando sulla documentazione di MDN vediamo che questa Api è sperimentale, perciò non è supportata ancora da tutti i browser. Interrogando il sito caniuse.com possiamo vedere che è implementata esclusivamente da Chrome, Opera e Firefox. Per fortuna è disponibile un polyfill di cui potete recuperare il codice in questo repository GitHub.
Let’s code
Partiamo con un primo esempio: una semplice animazione che muove un’immagine da sinistra verso destra tramite la proprietà left
. Il markup della nostra pagina è il seguente:
Abbiamo quindi un div
posizionato in maniera fissa e una button-bar che ci servirà per pilotare la nostra animazione. Lo script che utilizzeremo è il seguente:
var element = document.querySelector('.logo'); var keyframes = [ { left: "0px" }, { left: "500px" } ]; var timing = { duration: 2000, fill:"forwards", easing: 'ease-in-out' }; var effect = new KeyframeEffect(element, keyframes, timing); var animation = new Animation(effect, document.timeline); animation.onfinish = function () { document.querySelector('#label').textContent = 'Animation Finished on ' + new Date(); }; function play() { animation.play(); } function pause() { animation.pause(); } function reverse() { animation.reverse(); } function faster() { animation.playbackRate *= 2; } function slower() { animation.playbackRate /= 2; } var range = document.querySelector('#range'); range.addEventListener("input", function() { if (animation.playState === 'paused') { animation.currentTime = 2000 * range.value / 100; } }, false);
Per creare un’animazione dobbiamo innanzitutto creare un oggetto KeyframeEffect
a cui passiamo l’elemento del DOM a cui vogliamo applicare l’animazione i keyframes ed il timing. Usiamo poi questo oggetto per creare un Animation
e collegarla alla timeline della pagina. Notate che per definire l’animazione abbiamo utilizzato per le stesse proprietà che avremmo utilizzato per una normale animazione CSS. Una volta ottenuta l’animazione possiamo:
- Controllare l’animazione tramite i metodi
play
,pause
ereverse
- Possiamo invocare una callback alla fine dell’animazione tramite
onfinish
- Modificare la velocità (ed il verso) dell’animazione tramite la proprietà
playbackRate
- Posizionare l’animazione in un momento preciso nel tempo tramite la proprietà
currentTime
Potete provare questa animazione a questa pagina demo.
Gruppi e Sequenze
Come accennato all’inizio del post tramite le Web Animations Api possiamo anche animare gruppi di oggetti o creare una sequenza di animazioni. Vediamo subito il prossimo esempio sulla creazione dei gruppi. Per i prossimi esempi il markup sarà identico, avremo semplicemente più div
da muovere.
var firstLogo = document.querySelector('#firstLogo'); var secondLogo = document.querySelector('#secondLogo'); var firstKeyframes = [ { left: "0px" }, { left: "500px" } ]; var secondKeyframes = [ { right: "0px" }, { right: "500px" } ]; var firstTiming = { duration: 2000, fill:"forwards", easing: 'ease-in-out' }; var secondTiming = { duration: 4000, fill:"forwards", easing: 'ease-in-out' }; var effects = [ new KeyframeEffect(firstLogo, firstKeyframes, firstTiming), new KeyframeEffect(secondLogo, secondKeyframes, secondTiming) ]; var group = new GroupEffect(effects); var animation = new Animation(group,document.timeline); //Controllo animazione
In questo caso sfruttiamo l’oggetto GroupEffect
per wrappare un array di KeyframeEffect
. Il risultato sarà una serie di oggetti che si muovono contemporaneamente. Potete giocare con queste animazioni in questa demo. Vediamo come, in maniera del tutto similare, possiamo invece creare una sequenza.
var elements = document.querySelectorAll('.logo'); var effects = []; var keyframes = [ { left: "0px" }, { left: "500px" } ]; var timing = { duration: 2000, fill:"forwards", easing: 'ease-in-out' }; elements.forEach(function(element){ effects.push(new KeyframeEffect(element, keyframes, timing)); }); var sequence = new SequenceEffect(effects); var animation = new Animation(sequence,document.timeline); //Controllo animazione
Il codice è praticamente identico se non fosse per l’utilizzo dell’oggetto SequenceEffect
. Come per i precedenti esempi avete a disposizione una pagina demo.
Le due tecniche si posso ovviamente mescolare tra loro per ottenere delle animazioni davvero complesse come quella visibile in questo ultimo esempio. Provate a cliccare su “Full Screen” e notate come gli elementi scompaiono dallo schermo in sequenza.
Conclusioni
Qualcuno di voi potrebbe dire che lo stesso risultato lo si può ottenere con jQuery.animate, ma in realtà la differenza è sostanziale. Nei browser dove questa Api è supportata nativamente ha performance quasi del tutto identiche a quelle applicate tramite foglio di stile, per via del fatto che il browser sfrutta lo stesso engine delle animazioni CSS. Anche negli altri casi però le performance sono molto alte, come potete verificare voi stessi grazie a questo sito creato da Mozilla. Per chi è curioso il codice di tutti gli esempi è disponibile in questo repository GitHub. Alla prossima.