Animazioni e transizioni rappresentano una componente essenziale di qualsiasi user experience, in quanto garantiscono la fluidità della user interface e al tempo stesso aiutano l'utente a comprendere cosa sta accadendo sullo schermo. È importante però non eccedere nelle animazioni, per non distrarre o, peggio ancora, irritare l'utente stesso. Usate con giudizio, animazioni e transizioni rappresentano una parte integrante dell'ecosistema di Windows 8 e possono contribuire significativamente al successo delle nostre app.
Poiché sono basate sullo stesso engine di Internet Explorer, le applicazioni Windows Store scritte in HTML5/JavaScript supportano animazioni e transizioni basate sulla manipolazione di proprietà CSS, secondo le specifiche del nuovo CSS Level 3 (o CSS3, in breve).
Sebbene i termini "transizione" e "animazione" vengano generalmente usati in modo interscambiabile, esistono tuttavia alcune differenze. Secondo il W3C, in particolare, mentre le transizioni si basano su una serie di effetti predefiniti, su cui lo sviluppatore ha poco o nessun controllo, le animazioni permettono una maggiore flessibilità, grazie all'uso dei key frame per controllarne il flusso e alla possibilità di sospendere, riavvolgere o ripetere l'animazione stessa. Un'altra importante differenza risiede nel modo in cui transizioni e animazioni sono eseguite: una transizione viene eseguita al cambiare di una proprietà CSS (implicit transition), mentre un'animazione deve essere applicata in modo esplicito (explicit transition).
In questo articolo, vedremo come creare transizioni e animazioni per le nostre applicazioni Windows Store, ma anche come sfruttare l'Animation Library di Microsoft, un set di transizioni predefinite messe a disposizione dello sviluppatore (e racchiuse nel namespace WinJS.UI.Animation
) per migliorare, in modo semplice e trasparente, la user experience della propria applicazione senza dover ogni volta "reinventare la ruota".
Sfruttare le transizioni CSS
Una delle operazioni più comuni, quando si lavora con i CSS, è quella di modificare il valore di una o più proprietà di stile di un elemento, come cambiare il colore di un pulsante quando il puntatore del mouse viene posizionato sopra il controllo.
Prendiamo ad esempio il seguente stile CSS applicato a un elemento button
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Demo.Html.it.Animations.JS</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!-- Demo.Html.it.Animations.JS references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<style>
button {
width: 350px;
height: 100px;
border: 1px solid white;
background-color: green;
}
button:hover {
background-color: red;
}
</style>
</head>
<body>
<button>Hello!</button>
</body>
</html>
Muovendo il mouse sopra il pulsante, il colore di background cambia da verde a rosso. Tuttavia, questo cambiamento è decisamente repentino. Per rendere il passaggio più graduale, possiamo utilizzare una transizione. Per raggiungere questo risultato, modifichiamo lo stile come segue:
<style>
button {
width: 350px;
height: 100px;
border: 1px solid white;
background-color: green;
}
button:hover {
background-color: red;
/* introduciamo la transizione */
transition-property: background-color;
transition-duration: 2s;
transition-timing-function: linear;
}
</style>
Se eseguiamo nuovamente l'app, questa volta vedremo il colore cambiare progressivamente nell'arco di due secondi da verde a rosso, passando tramite una serie di colori intermedi. Una transizione si basa infatti sull'interpolazione, vale a dire su una serie di funzioni matematiche più o meno complesse che permettono di calcolare, dato il valore iniziale e il valore finale di una proprietà, i valori intermedi che questa assumerà in funzione del tempo.
In particolare, una transizione CSS3 si basa sulle seguenti proprietà:
Proprietà | Descrizione |
---|---|
transition-property | Indica la proprietà CSS da animare. Non tutte le proprietà possono essere animate. Per un elenco completo delle proprietà alle quali è possibile applicare una transizione si rinvia alle specifiche del W3C. La proprietà transition-property accetta anche due parole chiave:
|
transition-duration | Stabilisce la durata dell'animazione |
transition-timing-function | Specifica la funzione di interpolazione da utilizzare per calcolare i valori intermedi della proprietà in funzione del tempo. |
transition-delay | Se il valore è positivo, permette di differire l'esecuzione di una transizione. Un valore negativo, invece, determina un "taglio" dell'animazione (offset), che quindi inizierà ad essere eseguita dal punto indicato. |
È anche possibile animare più proprietà contemporaneamente, semplicemente aggiungendo nuove proprietà all'elenco, come mostrato nel seguente snippet:
<style>
button {
width: 350px;
height: 100px;
border: 1px solid white;
background-color: green;
}
button:hover {
background-color: red;
width: 320px;
transition-property: background-color, width;
transition-duration: 2s, 0.2s;
transition-timing-function: linear;
}
</style>
In questo codice, oltre al colore di background, ad essere animata sarà anche la larghezza del controllo. L'ordine con cui le proprietà da animare sono elencate nella transition-property
vale anche per determinare quale valore utilizzare per la durata e per la funzione di interpolazione: così, dal momento che nell'esempio proposto il valore width
è stato aggiunto per secondo, la durata dell'animazione per questa proprietà sarà pari al secondo valore passato come transition-duration
(ossia 0.2 secondi). Nel caso in cui il numero dei valori ecceda il numero di elementi passati come transition-property
, i valori in eccesso verranno semplicemente ignorati. Al contrario, se i valori passati sono in numero inferiore rispetto agli elementi da animare, come per il transition-timing-function
dell'esempio, l'elenco di questi valori verrà utilizzato per ricavare i valori mancanti (in questo caso, entrambe le animazioni useranno "linear" come funzione di interpolazione).
Come abbiamo accennato, la proprietà transition-timing-function
permette di specificare la funzione di interpolazione, ovvero come i valori intermedi di una proprietà vengono calcolati in funzione del tempo. Le specifiche CSS3 supportano diverse funzioni di interpolazione:
Funzione | Descrizione |
---|---|
ease | inizia lentamente, quindi accelera per poi rallentare nuovamente. |
linear | in questo caso la velocità dell'animazione rimane costante dall'inizio alla fine. |
ease-in | inizia lentamente per poi aumentare. |
ease-out | inizia rapidamente per poi rallentare. |
ease-in-out | più lenta all'inizio e alla fine (simile alla funzione "ease", ma più graduale nell'accelerazione e decelerazione). |
cubic-bezier | permette di specificare una curva di Bézier cubica (in realtà le funzioni viste finora non sono altro che particolari curve di Bézier). Questa funzione accetta due coppie di valori, nella forma (x1, y1, x2, y2), che identificano i due punti di controllo della curva. Questi valori devono essere compresi tra zero e uno (inclusi). |
steps | come il nome suggerisce, implica un'animazione a "gradini". Questa funzione accetta due parametri: il primo parametro (che deve essere un numero intero) specifica in quanti "gradini" l'animazione deve essere suddivisa (ciascun gradino ha la stessa durata), mentre il secondo parametro ("start" o "end") se il nuovo valore intermedio deve essere applicato all'inizio o alla fine del "gradino". |
step-start | equivale a steps(1, start) . |
step-end | equivale a steps(1, end) . |
Il seguente snippet mostra un esempio di transizione che sfrutta la funzione steps per animare un pulsante. L'animazione è suddivisa in 8 step e i valori intermedi della proprietà left sono applicati al termine della durata di ciascuno step.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Demo.Html.it.Animations.JS</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<!-- Demo.Html.it.Animations.JS references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<style>
button {
width: 350px;
height: 350px;
position: absolute;
top: 50px;
left: 0px;
border: 1px solid white;
background-color: green;
}
button:hover {
background-color: red;
left: 300px;
transition-property: left;
transition-duration: 8s;
transition-timing-function: steps(8, end);
}
</style>
</head>
<body>
<button>Hello!</button>
</body>
</html>
Eseguire codice JavaScript al termine di una transizione
L'evento transitionEnd viene sollevato ogni volta che l'animazione di una proprietà CSS termina, consentendo così di eseguire del codice JavaScript al termine dell'animazione stessa, ad esempio per applicare un'altra animazione o eseguire determinate azioni. È importante ricordare che, nel caso in cui la transizione riguardi più proprietà CSS, l'evento sarà sollevato una volta per ciascuna proprietà, indicando il nome della proprietà cui l'evento si riferisce e la durata della transizione.
Nell'esempio che segue, due sono le proprietà CSS che vengono animate: il colore di sfondo e il bordo del controllo (la durata dell'animazione e la funzione di interpolazione sono identici per le due animazioni).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Demo.Html.it.Animations.JS</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<!-- Demo.Html.it.Animations.JS references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<style>
#outerBox {
width: 350px;
height: 100px;
border: 1px solid white;
background-color: green;
}
#innerBox {
width: 100%;
height: 100%;
text-align: center;
}
#outerBox:hover {
background-color: red;
border: 10px solid yellow;
transition-property: background-color, border;
transition-duration: .5s;
transition-timing-function: cubic-bezier(.70, .35, .41, .78);
}
</style>
</head>
<body>
<div id="outerBox">
<div id="innerBox">
</div>
</div>
</body>
</html>
Il codice che segue si abbona all'evento transitionEnd per mostrare un messaggio a video al termine dell'animazione relativa al colore di background, mentre le transizioni relative all'elemento border verranno ignorate:
app.onloaded = function () {
outerBox.addEventListener("transitionend", onTransitionCompleted, false);
}
function onTransitionCompleted(args) {
if (args.propertyName == 'background-color') {
innerBox.innerHTML = "<p>Animazione completata</p>";
}
}
Se collocate un breakpoint in corrispondenza dell'istruzione if
all'interno dell'event handler, noterete infatti che l'evento transitionEnd
viene scatenato più volte. Questo vale anche per la proprietà border
, la quale non è altro che una "shorthand property", ossia una "scorciatoia" che permette di modificare in un solo colpo le singole proprietà di un bordo (in particolare, le proprietà border-width
, border-color
e border-style
per ciascuno dei quattro lati): noterete infatti che l'evento transitionEnd
sarà scatenato per ciascuna delle proprietà modificate dall'animazione (border-top-width
, border-top-color
, border-left-width
, ecc.).
Creare animazioni CSS3
La specifica CSS3 prevede non solo transizioni, ma anche animazioni. Come si è accennato, mentre le prime lasciano poco spazio alle personalizzazioni, potendo lo sviluppatore controllare solo alcuni elementi della transizione (ossia il valore iniziale e finale della proprietà, la durata della transizione e quale funzione di interpolazione applicare, tra quelle disponibili), le animazioni consentono un maggior controllo sull'intero flusso, grazie all'uso di key frame e a una serie di proprietà aggiuntive.
Un key frame permette di specificare i valori intermedi di una proprietà lungo la linea temporale dell'animazione (timeline). Il prossimo snippet mostra un esempio di animazione ottenuta tramite una serie di key frame che impostano il valore di alcune proprietà lungo la timeline:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Demo.Html.it.Animations.JS</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<!-- Demo.Html.it.Animations.JS references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<style>
#ball {
background-color: orange;
border-radius: 50%;
width: 160px;
height: 160px;
position: absolute;
bottom: 0;
left: 45%;
animation-name: bounceball;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-delay: 0;
animation-timing-function: ease-out;
animation-play-state: running;
animation-fill-mode: none;
}
@keyframes bounceball {
from {
bottom: 0;
height: 90px;
}
10% {
bottom: 0;
height: 160px;
}
to {
bottom: 70%;
}
}
</style>
</head>
<body>
<div id="ball"></div>
</body>
</html>
Per creare un'animazione, la prima cosa da fare è specificare le proprietà dell'animazione, a cominciare dal nome che identifica l'animazione stessa, espresso tramite la proprietà animation-name. Questo identificatore è utilizzato per selezionare i key frame che si riferiscono a quella particolare animazione.
Per creare uno o più key frame associati a una particolare animazione, occorre dichiararlo tramite una dichiarazione CSS preceduta dal carattere "@
" (e per questo definita come "CSS at-rule"). La parola chiave è infatti "@keyframes
", seguita dall'identificativo associato all'animazione cui quei key frame si riferiscono (e rappresentato dalla proprietà animation-name
) e da un insieme di regole di stile CSS:
@keyframes bounceball {
from {
bottom: 0;
height: 90px;
}
10% {
bottom: 0;
height: 160px;
}
to {
bottom: 70%;
}
}
Come si vede, ogni singolo key frame all'interno della sequenza individua un particolare punto nella timeline. Questi punti vengono identificati con un numero percentuale (riferiti alla durata complessiva dell'animazione). Per identificare il punto iniziale e quello finale di un'animazione, ossia 0% e 100%, è possibile anche utilizzare le parole chiave from e to, come nell'esempio proposto.
All'interno di un key frame, è possibile specificare le proprietà da animare e indicare il loro valore in quel particolare punto della timeline (le proprietà che possono essere animate sono le stesse che valgono per le transizioni, per un elenco completo si rinvia alle specifiche del W3C).
Dal momento che sono i key frame a specificare le proprietà da animare, se il nome assegnato a un'animazione non coincide con nessun key frame, vuol dire che non ci sono proprietà che devono essere animate, e l'animazione non verrà eseguita. Lo stesso accade se il nome assegnato all'animazione è "none", parola riservata che indica appunto che l'animazione non deve essere eseguita. Inoltre, se più animazioni stanno cercando di modificare la stessa proprietà, a prevalere (e quindi ad essere applicata) sarà l'ultima animazione nell'elenco (come appunto accade con gli stili CSS).
La proprietà animation-duration specifica invece la durata dell'animazione e accetta un numero a virgola mobile. Può essere espressa in secondi (s) o millisecondi (ms).
La proprietà animation-timing-function consente di indicare il tipo di interpolazione da utilizzare per determinare i valori intermedi tra due successivi key frame. Come per le transizioni, anche in questo caso è possibile scegliere la funzione di interpolazione tra quelle disponibili.
Le funzioni di interpolazione disponibili sono sostanzialmente le stesse viste per le transizioni (mancano le "scorciatoie" rappresentate dalle funzioni step-end e step-start), al cui paragrafo pertanto si rinvia. Nel caso delle animazioni, le funzioni di interpolazione possono essere usate non solo nel "corpo" dell'animazione, come nell'esempio sopra (in questo caso la funzione verrà applicata a tutti i key frame che compongono l'animazione), ma anche all'interno dei singoli key frame. Il prossimo snippet mostra una versione modificata dell'animazione vista sopra, che imposta una diversa funzione di interpolazione per ciascuno dei key frame:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Demo.Html.it.Animations.JS</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<!-- Demo.Html.it.Animations.JS references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<style>
#ball {
background-color: orange;
border-radius: 50%;
width: 160px;
height: 160px;
position: absolute;
bottom:160px;
left: 45%;
animation-name: bounceball;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-delay: 0;
animation-play-state: running;
animation-fill-mode: none;
}
@keyframes bounceball {
0% {
bottom: 0;
animation-timing-function: ease-out;
}
100% {
bottom: 300px;
animation-timing-function: ease-in;
}
}
</style>
</head>
<body>
<div id="ball"></div>
</body>
</html>
Altre proprietà dell'animazione sono:
- animation-delay, che permette di ritardare l'esecuzione di un'animazione;
- animation-iteration-count, che consente di specificare quante volte l'animazione deve essere ripetuta ( il valore di default è 1; un valore di "infinite", come nell'esempio, indica un loop senza fine);
- animation-play-state, tramite la quale è possibile mettere in pausa e successivamente riprendere l'animazione dal punto in cui era stata messa in pausa (questa proprietà accetta i valori "running" e "paused");
- animation-fill-mode, che definisce quali valori applicare ad una proprietà al termine dell'applicazione (per aprofondimenti su questa proprietà si rinvia alle specifiche del W3C);
- nonché animation-direction, per modificare il flusso normale dell'animazione tra un ciclo e l'altro.
Quest'ultima proprietà, in particolare, può assumere uno dei seguenti valori:
Valore | Descrizione |
---|---|
normal | l'animazione viene eseguita normalmente; a ogni ciclo l'animazione riprende dall'inizio (è il valore di default); |
alternate | il flusso dell'animazione viene invertito a ogni ciclo. Quando l'animazione viene eseguita al contrario, anche le funzioni di interpolazione vengono ribaltate (ad esempio, ease-in diviene ease-out ). |
reverse | l'animazione viene eseguita al contrario a ogni ciclo; al termine di ogni ciclo viene ripristinato il valore finale di una proprietà e l'animazione comincia nuovamente. |
alternate-reverse | come per alternate , ma in questo caso la prima esecuzione avviene al contrario. |
Come per altre proprietà CSS, anche per le animazioni è prevista una scorciatoia, rappresentata dalla proprietà animation, la quale permette di specificare uno o più insiemi di proprietà dell'animazione separati da spazi. I valori della proprietà dell'animazione devono essere impostati nell'ordine seguente:
animation-name
animation-duration
animation-timing-function
animation-delay
animation-iteration-count
animation-direction
Se vi è più di un valore per le diverse proprietà dell'animazione, questi devono essere separati da una virgola. Il prossimo snippet ne mostra un esempio:
animation: bounceball 2s ease-out 0 infinite alternate;
In questo articolo abbiamo visto come creare transizioni e animazioni per la UI della nostra applicazione Windows Store. Nel prossimo articolo, invece, vedremo come sfruttare l'Animation Library, un set di transizioni predefinite messo a disposizione da Microsoft per semplificare il lavoro degli sviluppatori e garantire al contempo l'omogeneità della user experience in un'applicazione Windows Store.