Le animazioni CSS ci consentono di realizzare semplici animazioni senza lutilizzo di JavaScript.
JavaScript pu eventualmente essere utilizzato per controllare le animazioni CSS e migliorarle, aggiungendo qualche riga di codice.
Transizioni CSS
Lidea che sta alla base delle transizioni CSS molto semplice. Ci consente di definire come animare i cambiamenti su una determinata propriet. Quando il valore di questa propriet cambier, il browser mostrer lanimazione.
Questo tutto, lunica cosa di cui abbiamo bisogno ora di cambiare il valore della propriet, e la transizione definita verr eseguita dal browser.
Ad esempio, il codice CSS qui sotto definisce unanimazione al cambiamento della propriet background-color con durata 3 secondi:
.animated {
transition-property: background-color;
transition-duration: 3s;
}
Quindi ora, se un elemento possiede la class .animated, qualsiasi cambiamento al suo background-color verr animato con una durata di 3 secondi.
Provate a cliccare il bottone qui sotto per vedere lanimazione sul background:
<button id="color">Click me</button>
<style>
#color {
transition-property: background-color;
transition-duration: 3s;
}
</style>
<script>
color.onclick = function() {
this.style.backgroundColor = 'red';
};
</script>
Abbiamo a disposizione 4 propriet per descrivere le transizioni CSS:
transition-propertytransition-durationtransition-timing-functiontransition-delay
Le studieremo in dettaglio a breve, per ora notiamo che la propriet comune transition ci consente di dichiararle tutte insieme nellordine: property duration timing-function delay, e ci consente anche di definire pi propriet da animare.
Ad esempio, nel bottone qui sotto abbiamo definito unanimazione sia su color che su font-size:
<button id="growing">Click me</button>
<style>
#growing {
transition: font-size 3s, color 2s;
}
</style>
<script>
growing.onclick = function() {
this.style.fontSize = '36px';
this.style.color = 'red';
};
</script>
Ora, vediamo le propriet dellanimazione nel dettaglio.
transition-property
In transition-property, elenchiamo una lista di propriet da animare, ad esempio: left, margin-left, height, color. Oppure possiamo scrivere all, che significa anima tutte le propriet.
Notiamo che ci sono propriet che non possono essere animate. Anche se la maggior parte delle propriet utilizzate sono animabili.
transition-duration
In transition-duration possiamo definire la durata dellanimazione. Il tempo deve essere nel formato temporale CSS: in secondi s o millisecondi ms.
transition-delay
In transition-delay possiamo specificare un ritardo dellanimazione. Ad esempio, se transition-delay impostato ad 1s e transition-duration vale 2s, allora lanimazione inizier con 1 secondo di ritardo rispetto al cambiamento del valore della propriet a cui fa riferimento, e avr una durata totale di 2 secondi.
E possibile definire anche valori negativi. In questo caso lanimazione inizier immediatamente, ma il punto di inizio verr spostato di tanti secondi quanti sono quelli del tempo di ritardo fornito. Ad esempio, se transition-delay impostato a -1s e transition-duration vale 2s, lanimazione inizier a met ed avr una durata totale di 1 secondo.
Qui vediamo un animazione che scorre le cifre da 0 a 9 utilizzando la propriet CSS translate:
stripe.onclick = function() {
stripe.classList.add('animate');
};#digit {
width: .5em;
overflow: hidden;
font: 32px monospace;
cursor: pointer;
}
#stripe {
display: inline-block
}
#stripe.animate {
transform: translate(-90%);
transition-property: transform;
transition-duration: 9s;
transition-timing-function: linear;
}<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
Click below to animate:
<div id="digit"><div id="stripe">0123456789</div></div>
<script src="script.js"></script>
</body>
</html>La propriet transform viene animata in questo modo:
#stripe.animate {
transform: translate(-90%);
transition-property: transform;
transition-duration: 9s;
}
Nellesempio visto sopra, JavaScript aggiunge la classe .animate allelemento, iniziando cos lanimazione:
stripe.classList.add('animate');
Possiamo anche iniziarla a met della transizione, da un numero specifico, ad esempio corrispondente al secondo attuale, utilizzando un valore negativo per la propriet transition-delay.
Nellesempio sotto, se cliccate il numero, lanimazione inizier dal secondo attuale:
stripe.onclick = function() {
let sec = new Date().getSeconds() % 10;
stripe.style.transitionDelay = '-' + sec + 's';
stripe.classList.add('animate');
};#digit {
width: .5em;
overflow: hidden;
font: 32px monospace;
cursor: pointer;
}
#stripe {
display: inline-block
}
#stripe.animate {
transform: translate(-90%);
transition-property: transform;
transition-duration: 9s;
transition-timing-function: linear;
}<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
Click below to animate:
<div id="digit"><div id="stripe">0123456789</div></div>
<script src="script.js"></script>
</body>
</html>Con JavaScript possiamo fare la stessa cosa, ma con qualche riga di codice in pi:
stripe.onclick = function() {
let sec = new Date().getSeconds() % 10;
// ad esempio, -3s in questo caso, far iniziare l'animazione al terzo secondo
stripe.style.transitionDelay = '-' + sec + 's';
stripe.classList.add('animate');
};
transition-timing-function
La funzione di temporizzazione permette di descrivere la distribuzione dellanimazione lungo la sua durata. Potr iniziare pi lenta e poi accelerare, o vice versa.
A prima vista sembra essere una delle propriet pi complesse. Ma diventa piuttosto semplice se ci dedichiamo un po di tempo per capirla.
Questa propriet accetta due tipi di valore: una curva di Bezier oppure degli step. Iniziamo a vedere il caso in cui si utilizza la curva di Bezier, poich il pi comune.
Bezier curve
La funziona di temporizzazione pu essere definita utilizzando una curva di Bezier con 4 punti di controllo che soddisfino le seguenti condizioni:
- Il primo punto di controllo deve essere:
(0,0). - Lultimo punto di controllo deve essere:
(1,1). - Per i valori intermedi, il valore di
xdeve essere compreso nellintervallo0..1, mentreypu assumere qualsiasi valore.
La sintassi per descrivere una curva di Bezier nel CSS: cubic-bezier(x2, y2, x3, y3). In questo caso necessario specificare solamente il terzo ed il quarto punto di controllo, poich il primo viene impostasto a (0,0) ed il quarto a (1,1).
La funzione di temporizzazione descrive la velocit di riproduzione dellanimazione.
- Lasse delle
xrappresenta il tempo:0linizio,1il termine dellanimazione, specificato intransition-duration. - Lasse delle
yspecifica il completamento del processo:0il valore iniziale della propriet,1il valore finale.
La variante pi semplice quando unanimazione procede uniformemente, con velocita lineare. Questo tipo di animazione pu essere definito con la curva cubic-bezier(0, 0, 1, 1).
Cos come appare la curva descritta:
Come possiamo vedere, una semplice linea retta. Al passare del tempo (x), il completamento (y) dellanimazione passa da 0 a 1.
Il treno nellesempio sotto va da sinistra verso destra con velocit costante (provate a cliccarci sopra):
.train {
position: relative;
cursor: pointer;
width: 177px;
height: 160px;
left: 0;
transition: left 5s cubic-bezier(0, 0, 1, 1);
}<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<img class="train" src="https://js.cx/clipart/train.gif" onclick="this.style.left='450px'">
</body>
</html>La transition CSS basata su questa curva:
.train {
left: 0;
transition: left 5s cubic-bezier(0, 0, 1, 1);
/* JavaScript imposta left a 450px */
}
Come potremmo mostrare il treno che rallenta?
Possiamo utilizzare una curva di Bezier differente: cubic-bezier(0.0, 0.5, 0.5 ,1.0).
La curva appare cos:
Come possiamo vedere, il processo inizia velocemente: la curva cresce verso lalto, e successivamente rallenta.
Qui vediamo la funzione di temporizzazione in azione (cliccate il treno):
.train {
position: relative;
cursor: pointer;
width: 177px;
height: 160px;
left: 0px;
transition: left 5s cubic-bezier(0.0, 0.5, 0.5, 1.0);
}<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<img class="train" src="https://js.cx/clipart/train.gif" onclick="this.style.left='450px'">
</body>
</html>CSS:
.train {
left: 0;
transition: left 5s cubic-bezier(0, .5, .5, 1);
/* JavaScript imposta left a 450px */
}
Abbiamo a disposizione anche alcune curve integrate: linear, ease, ease-in, ease-out e ease-in-out.
La curva linear un abbreviazione per cubic-bezier(0, 0, 1, 1), una linea retta, che abbiamo descritto sopra.
Gli altri nomi sono delle abbreviazioni per le seguenti curve cubic-bezier:
ease* |
ease-in |
ease-out |
ease-in-out |
|---|---|---|---|
(0.25, 0.1, 0.25, 1.0) |
(0.42, 0, 1.0, 1.0) |
(0, 0, 0.58, 1.0) |
(0.42, 0, 0.58, 1.0) |
* di default, se non viene fornita nessuna funzione di temporizzazione, verr utilizzata ease.
Potremmo quindi utilizzare ease-out per rallentare lanimazione del treno:
.train {
left: 0;
transition: left 5s ease-out;
/* same as transition: left 5s cubic-bezier(0, .5, .5, 1); */
}
Anche se apparir leggermente diversa.
Una curva di Bezier pu far eccedere lanimazione dal suo intervallo.
I punti di controllo nella curva, sono liberi di definire un valore qualsiasi per le coordindate y: sia valori grandi che negativi. Questo si rifletter sulla curva di Bezier che potr essere molto alta o molto bassa, facendo eccedere lanimazione dal suo intervallo normale.
Nellesempio sotto il codice dellanimazione :
.train {
left: 100px;
transition: left 5s cubic-bezier(.5, -1, .5, 2);
/* JavaScript imposta left a 400px */
}
La propriet left sar animata da 100px a 400px.
Ma se provate a cliccare il treno, vedrete che:
- Primo, il treno va indietro:
leftdiventa inferiore a100px. - Poi va in avanti, leggermente oltre i
400px. - E successivamente torna nuovamente indietro, fino a
400px.
.train {
position: relative;
cursor: pointer;
width: 177px;
height: 160px;
left: 100px;
transition: left 5s cubic-bezier(.5, -1, .5, 2);
}<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<img class="train" src="https://js.cx/clipart/train.gif" onclick="this.style.left='400px'">
</body>
</html>Ci che accadde abbastanza ovvio, se andiamo a guardare il grafico della curva di Bezier:
Abbiamo impostato la coordinata y del secondo punto, sotto lo zero, ed il terzo punto va oltre 1, quindi la curva esce dal quadrante standard. La y eccede quindi lintervallo standard 0..1.
Come sappiamo, y misura il grado di completezza dellanimazione. Il valore y = 0 corrisponde al valore iniziale della propriet, mentre y = 1 corrisponde al valore finale. Quindi i valori di y<0 spostando la propriet sotto il valore iniziale di left e y>1 oltre il valore finale di left.
Questa ovviamente una variante pi leggera. Se impostiamo y a valori come -99 e 99 allora il treno eccederebbe lintervallo pi evidentemente.
Ma come possiamo definire una curva di Bezier per una specifica animazione? Esistono diversi strumenti che ci permettono di farlo. Ad esempio, possiamo utilizzare http://cubic-bezier.com/.
Steps
La funzione di temporizzazione steps(number of steps[, start/end]) consente di definire unanimazione in steps (passi).
Vediamolo in azione su un esempio con cifre.
Qui abbiamo unelenco di cifre, senza alcuna animazione:
#digit {
border: 1px solid red;
width: 1.2em;
}
#stripe {
display: inline-block;
font: 32px monospace;
}<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="digit"><div id="stripe">0123456789</div></div>
</body>
</html>Ci che faremo sar far apparire le cifre in modo discreto facendo si che la lista esterna al box rosso sia invisibile, e faremo scorrere la lista a sinistra ad ogni step.
Dovremo definire 9 step, uno per ogni cifra:
#stripe.animate {
transform: translate(-90%);
transition: transform 9s steps(9, start);
}
In azione:
#digit {
width: .5em;
overflow: hidden;
font: 32px monospace;
cursor: pointer;
}
#stripe {
display: inline-block
}
#stripe.animate {
transform: translate(-90%);
transition-property: transform;
transition-duration: 9s;
transition-timing-function: steps(9, start);
}<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
Click below to animate:
<div id="digit"><div id="stripe">0123456789</div></div>
<script>
digit.onclick = function() {
stripe.classList.add('animate');
}
</script>
</body>
</html>Il primo argomento di steps(9, start) il numero di step. La transform verr divisa in 9 parti (10% ad ognuna). Anche lintervallo di tempo sar diviso automaticamente in 9 parti, quindi transition: 9s far durare lanimazione 9 secondi, 1 secondo per ogni cifra.
Il secondo argomento una delle due parole chiave: start o end.
La parola chiave start significa che il primo step verr eseguito immediatamente allinizio dellanimazione.
Possiamo osservarlo durante lanimazione: quando clicchiamo su una cifra cambia ad 1 (il primo step) immediatamente, e successivamente cambier al termine del secondo successivo.
Il processo progredir in questo modo:
0s-10%(il primo cambiamento allinizio del primo secondo, immediatamente)1s-20%8s-80%- (lultimo secondo mostra il valore finale).
In alternativa il valore end star a significare che il cambiamento dovrebbe essere applicato non dallinizio, ma alla fine di ogni secondo.
Il processo progredir in questo modo:
0s01s-10%(il primo cambiamento alla fine del primo secondo)2s-20%9s-90%
Qui vediamo steps(9, end) in azione (da notare la pausa tra il cambiamento della prima cifra):
#digit {
width: .5em;
overflow: hidden;
font: 32px monospace;
cursor: pointer;
}
#stripe {
display: inline-block
}
#stripe.animate {
transform: translate(-90%);
transition-property: transform;
transition-duration: 9s;
transition-timing-function: steps(9, end);
}<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
Click below to animate:
<div id="digit"><div id="stripe">0123456789</div></div>
<script>
digit.onclick = function() {
stripe.classList.add('animate');
}
</script>
</body>
</html>Anche in questo caso esistono delle abbreviazioni:
step-startequivale asteps(1, start). Ovvero, lanimazione inizier immediatamente e compier il primo step. Quindi inizier e terminer immediatamente, come se non ci fosse alcuna animazione.step-endequivale asteps(1, end): compie lanimazione in un solo step al termine ditransition-duration.
Questi valori vengono utilizzati raramente. Poich non definiscono delle vere animazioni, ma piuttosto un cambiamento di un solo step.
Levento transitionend
Al termine dellanimazione CSS, verr innescato levento transitionend.
Viene spesso utilizzato per compiere unazione al termine dellanimazione. In questo modo possiamo unire le animazioni.
Ad esempio, la nave che vediamo nellesempio sotto inizia a navigare quando cliccata, e poi torna indietro, ogni volta si allontana sempre di pi verso destra:
Lanimazione viene avviata dalla funzione go che viene rieseguita al termine di ogni transizione, invertendo la direzione:
boat.onclick = function() {
//...
let times = 1;
function go() {
if (times % 2) {
// naviga verso destra
boat.classList.remove('back');
boat.style.marginLeft = 100 * times + 200 + 'px';
} else {
// naviga verso sinistra
boat.classList.add('back');
boat.style.marginLeft = 100 * times - 200 + 'px';
}
}
go();
boat.addEventListener('transitionend', function() {
times++;
go();
});
};
Loggetto emesso dallevento transitionend possiede un paio di propriet specifiche:
event.propertyName- La propriet che ha concluso lanimazione. Pu essere utile se abbiamo definito animazioni per pi propriet.
event.elapsedTime- Il tempo (in secondi) impiegato per concludere lanimazione, senza considerare
transition-delay.
Keyframes
Possiamo unire tra di loro pi animazioni utilizzando la regola CSS @keyframes.
Tale regola specifica il nome dellanimazione e le modalit: cosa, quando e dove eseguire lanimazione. Successivamente, utilizzando la propriet animation, possiamo attribuire lanimazione allelemento ed eventualmente specificare parametri addizionali.
Qui vediamo unesempio commentato:
<div class="progress"></div>
<style>
@keyframes go-left-right { /* gli diamo un nome: "go-left-right" */
from { left: 0px; } /* anima da sinistra: 0px */
to { left: calc(100% - 50px); } /* anima verso sinistra: 100%-50px */
}
.progress {
animation: go-left-right 3s infinite alternate;
/* applichiamo l'animazione "go-left-right" all'elemento
durata 3 secondi
ripetizioni: infinite
alterna le direzione ad ogni iterazione
*/
position: relative;
border: 2px solid green;
width: 50px;
height: 20px;
background: lime;
}
</style>
Potete trovare molti articoli sul tema @keyframes e la specifica dettagliata.
Probabilmente non avrete bisogno di utilizzare @keyframes spesso, a meno che tutto nel vostro sito sia in costante movimento.
Riepilogo
Le animazioni CSS consentono di definire delle animazioni fluide (o meno) su una o pi propriet CSS.
Sono utili nella maggior parte dei casi in cui dobbiamo definire delle animazioni. Possiamo anche utilizzare JavaScript per definire le animazioni, ed il prossimo capitolo sar infatti dedicato a questo.
Le limitazioni delle animazioni CSS rispetto a quelle definite utilizzando JavaScript:
- Le cose semplici sono facili da realizzare.
- Pi veloci e leggere per la CPU.
- Le animazioni JavaScript sono pi flessibili. Possono implementare qualsiasi logica, come un esplosione di un elemento.
- Non si limitano a cambiamenti di propriet. Con JavaScript possiamo anche creare nuovi elementi da aggiungere allanimazione.
La maggior parte delle animazioni possono essere implementate con CSS come descritto in questo articolo. Insieme allevento transitionend possiamo eseguire codice al termine dellanimazione, integrandoci perfettamente con lanimazione.
Nel prossimo articolo vedremo le animazioni con JavaScript, andando a trattare casi pi complessi.
Commenti
<code>, per molte righe includile nel tag<pre>, per pi di 10 righe utilizza una sandbox (plnkr, jsbin, codepen)