Come avvicinarsi alle animazioni SVG nei CSS
Pubblicato: 2022-03-11Le animazioni sono una parte onnipresente del web. A differenza delle immagini GIF lampeggianti che affliggevano i siti Web nei primi giorni di Internet, le animazioni di oggi sono più sottili e di buon gusto. Designer e specialisti del front-end li utilizzano per rendere i siti Web più raffinati, migliorare l'esperienza dell'utente, richiamare l'attenzione su elementi importanti e trasmettere informazioni.
Gli sviluppatori Web possono trarre vantaggio dalla combinazione della potenza di SVG e CSS per creare animazioni senza utilizzare librerie esterne. Questo tutorial di animazione SVG mostra come creare animazioni personalizzate per progetti del mondo reale.
Animazione SVG utilizzando CSS: concetti fondamentali
Prima di animare gli SVG con CSS, gli sviluppatori devono capire come funzionano internamente gli SVG. Fortunatamente è simile all'HTML: definiamo gli elementi SVG con la sintassi XML e li stiliamo con CSS, proprio come se fossero HTML.
Gli elementi SVG sono costruiti appositamente per disegnare grafica. Possiamo usare <rect> per disegnare un rettangolo, <circle> per disegnare cerchi, ecc.—SVG definisce anche <ellipse> , <line> , <polyline> , <polygon> e <path> .
Nota: l'elenco completo degli elementi SVG include anche <animate> , che consente di creare animazioni utilizzando il linguaggio di integrazione multimediale sincronizzato (SMIL). Tuttavia, il suo futuro è incerto e il team di Chromium consiglia di utilizzare un approccio basato su CSS o JavaScript per animare gli SVG quando possibile.
Gli attributi disponibili dipendono dall'elemento, quindi mentre <rect> ha attributi di width e height , l'elemento <circle> ha l'attributo r , che ne definisce il raggio.
Mentre la maggior parte degli elementi HTML può avere figli, la maggior parte degli elementi SVG no. Un'eccezione è l'elemento di gruppo <g> , che possiamo utilizzare per applicare stili CSS e trasformazioni a più elementi contemporaneamente.
L'elemento <svg> e i suoi attributi
Un'altra importante differenza tra HTML e SVG è il modo in cui posizioniamo gli elementi, in particolare tramite l'attributo viewBox di un dato elemento <svg> esterno. Il suo valore è costituito da quattro numeri separati da spazi bianchi o da una virgola: min-x , min-y , width e height . Insieme, questi specificano la quantità del nostro disegno SVG che vogliamo che il browser visualizzi. Quell'area verrà ridimensionata per adattarsi ai limiti del viewport , come definito dagli attributi di width e height dell'elemento <svg> .
Quando si tratta di letterbox, il rapporto tra gli attributi di width e height del viewport può effettivamente differire dal rapporto tra le parti di width e height dell'attributo viewBox .
Per impostazione predefinita, le proporzioni della tela SVG verranno mantenute a scapito di un viewBox più grande di quanto specificato, causando così un rendering letterbox più piccolo all'interno del viewport. Ma puoi specificare un comportamento diverso tramite l'attributo preserveAspectRatio .
Questo ci consente di disegnare immagini in isolamento e di essere sicuri che tutti gli elementi saranno posizionati correttamente, indipendentemente dal contesto o dalle dimensioni del rendering.
Sebbene tu possa codificare manualmente le immagini SVG, le immagini più complesse potrebbero richiedere un programma di grafica vettoriale (il nostro tutorial di animazione SVG mostra entrambe le tecniche). Il mio editor preferito è Affinity Designer, ma qualsiasi editor dovrebbe fornire funzionalità sufficienti per le semplici operazioni trattate qui.
Transizioni e animazioni CSS
Le transizioni CSS ci consentono di definire la velocità e la durata delle modifiche alle proprietà. Invece di saltare istantaneamente dal valore iniziale al valore finale, i valori passano in modo fluido come in questo esempio in cui il colore di un cerchio SVG cambia quando ci passi sopra con il mouse:
Guarda l'esempio Pen Transition di Filip Defar (@dabrorius) su CodePen.
Possiamo definire le transizioni con la proprietà di transition , che accetta il nome della proprietà che vogliamo trasferire, la durata della transizione, una funzione di temporizzazione della transizione (nota anche come funzione di andamento) e la durata del ritardo prima dell'inizio dell'effetto :
/* property name | duration | easing function | delay */ transition: margin-right 4s ease-in-out 1s;Possiamo definire transizioni per più proprietà CSS, ognuna delle quali può avere valori di transizione separati. Tuttavia, ci sono due ovvi limiti a questo approccio.
La prima limitazione è che le transizioni vengono attivate automaticamente quando cambia il valore di una proprietà. Questo è scomodo in alcuni casi d'uso. Ad esempio, non possiamo avere un'animazione che si ripete all'infinito.
La seconda limitazione è che le transizioni hanno sempre due passaggi: lo stato iniziale e lo stato finale. Possiamo estendere la durata dell'animazione, ma non possiamo aggiungere fotogrammi chiave diversi.
Ecco perché esiste un concetto più potente: le animazioni CSS. Con le animazioni CSS, possiamo avere più fotogrammi chiave e un ciclo infinito:
Guarda l'esempio di Pen Animation di Filip Defar (@dabrorius) su CodePen.
Per animare le proprietà CSS su più fotogrammi chiave, dobbiamo prima definire i fotogrammi chiave usando una regola @keyframes . La tempistica dei fotogrammi chiave è definita in unità relative (percentuali) perché a questo punto non abbiamo ancora definito la durata dell'animazione. Ogni fotogramma chiave descrive i valori di una o più proprietà CSS in quel momento. Le animazioni CSS garantiranno transizioni fluide tra i fotogrammi chiave.
Applichiamo l'animazione con i fotogrammi chiave descritti all'elemento desiderato utilizzando la proprietà di animation . Simile alla proprietà di transition , accetta una durata, una funzione di andamento e un ritardo.
L'unica differenza è che il primo parametro è il nostro nome @keyframes invece del nome di una proprietà:
/* @keyframes name | duration | easing-function | delay */ animation: my-sliding-animation 3s linear 1s;Animazione di un menu Hamburger Toggle
Ora che abbiamo una conoscenza di base di come funziona l'animazione degli SVG, possiamo iniziare a creare un'animazione classica, un menu che alterna facilmente tra un'icona "hamburger" e un pulsante di chiusura (una "X"):
Guarda il Pen Hamburger di Filip Defar (@dabrorius) su CodePen.
Questa è un'animazione sottile ma preziosa. Attira l'attenzione dell'utente, informandolo che l'icona può essere utilizzata per chiudere il menu.
Iniziamo la nostra dimostrazione creando un elemento SVG con tre righe:
<svg class="hamburger"> <line x1="0" y1="50%" x2="100%" y2="50%" class="hamburger__bar hamburger__bar--top" /> <line x1="0" y1="50%" x2="100%" y2="50%" class="hamburger__bar hamburger__bar--mid" /> <line x1="0" y1="50%" x2="100%" y2="50%" class="hamburger__bar hamburger__bar--bot" /> </svg> Ogni riga ha due serie di attributi. x1 e y1 rappresentano le coordinate dell'inizio della linea, mentre x2 e y2 rappresentano le coordinate della fine della linea. Abbiamo usato le unità relative per impostare le posizioni. Questo è un modo semplice per garantire che il contenuto dell'immagine venga ridimensionato per adattarsi all'elemento SVG che lo contiene. Sebbene questo approccio funzioni in questo caso, c'è un grosso svantaggio: non possiamo mantenere le proporzioni degli elementi posizionati in questo modo. Per questo, dovremmo usare l'attributo viewBox dell'elemento <svg> .
Nota che abbiamo applicato le classi CSS agli elementi SVG. Ci sono molte proprietà che possono essere modificate tramite CSS, quindi applichiamo alcuni stili di base ai nostri elementi SVG.
Imposteremo la dimensione dell'elemento <svg> e cambieremo il tipo di cursore per indicare che è selezionabile. Ma per impostare il colore e lo spessore delle linee, utilizzeremo le proprietà del stroke e stroke-width . Potresti aspettarti di usare color o border , ma a differenza di <svg> stesso, i sottoelementi SVG non sono elementi HTML, quindi spesso hanno nomi di proprietà diversi:
.hamburger { width: 62px; height: 62px; cursor: pointer; } .hamburger__bar { stroke: white; stroke-width: 10%; } Se eseguiamo il rendering a questo punto, vedremo che tutte e tre le linee hanno la stessa dimensione e posizione, sovrapponendosi completamente l'una all'altra. Sfortunatamente, non possiamo modificare la posizione iniziale e finale in modo indipendente tramite CSS, ma possiamo spostare interi elementi. Spostiamo le barre superiore e inferiore con la proprietà CSS di transform :
.hamburger__bar--top { transform: translateY(-40%); } .hamburger__bar--bot { transform: translateY(40%); }Spostando le barre sull'asse Y ci ritroviamo con un hamburger dall'aspetto decente.
Ora è il momento di codificare il nostro secondo stato: il pulsante di chiusura. Facciamo affidamento su una classe CSS .is-opened applicata all'elemento SVG per passare da uno stato all'altro. Per rendere il risultato più accessibile, avvolgiamo il nostro SVG in un elemento <button> e gestiamo i clic su quel livello.
Il processo di aggiunta e rimozione della classe sarà gestito da un semplice snippet JavaScript:
const hamburger = document.querySelector("button"); hamburger.addEventListener("click", () => { hamburger.classList.toggle("is-opened"); }); Per creare la nostra X, possiamo applicare una proprietà di transform diversa alle nostre barre di hamburger. Poiché la nuova proprietà di transform sostituirà quella precedente, il nostro punto di partenza sarà la posizione originale condivisa delle tre barre.
Da lì, possiamo ruotare la barra superiore di 45 gradi in senso orario attorno al suo centro e ruotare la barra inferiore di 45 gradi in senso antiorario. Possiamo ridurre la barra centrale orizzontalmente finché non è abbastanza stretta da essere nascosta dietro il centro della X:
.is-opened .hamburger__bar--top { transform: rotate(45deg); } .is-opened .hamburger__bar--mid { transform: scaleX(0.1); } .is-opened .hamburger__bar--bot { transform: rotate(-45deg); } Per impostazione predefinita, la proprietà transform-origin per gli elementi SVG è normalmente 0,0 . Ciò significa che le nostre barre verranno ruotate attorno all'angolo in alto a sinistra della finestra, ma vogliamo che ruotino attorno al centro. Per risolvere questo problema, impostiamo la proprietà transform-origin al center della classe .hamburger__bar .

Animazione delle proprietà CSS con transition
La proprietà CSS di transition indica al browser di passare senza problemi tra due diversi stati delle proprietà CSS. Qui vogliamo animare le nostre modifiche alla proprietà transform , che determina le posizioni, l'orientamento e la scala delle barre.
Possiamo anche controllare la durata della transizione usando la proprietà della transition-duration della transizione. Per rendere l'animazione scattante, imposteremo una breve durata di 0,3 secondi:
.hamburger__bar { transition-property: transform; transition-duration: 0.3s; ... }L'unico pezzo di JavaScript di cui abbiamo bisogno è il bit che rende lo stato dell'icona commutabile:
const hamburger = document.querySelector("button"); hamburger.addEventListener("click", () => { hamburger.classList.toggle("is-opened"); }); Qui, selezioniamo l'elemento SVG esterno in base alla sua classe .mute usando querySelector() . Quindi aggiungiamo un listener di eventi clic. Quando viene attivato un evento click, si attiva o disattiva la classe .is-active solo sullo stesso <svg> , non più in profondità nella gerarchia. Poiché abbiamo applicato l'animazione CSS solo agli elementi con la classe .is-active , l'attivazione/disattivazione di questa classe attiverà e disattiverà l'animazione.
Come tocco finale, convertiremo il corpo HTML in un contenitore flessibile, che ci aiuterà a centrare l'icona orizzontalmente e verticalmente. Aggiorneremo anche il colore di sfondo in un grigio molto scuro e il colore dell'icona in bianco, per ottenere un aspetto elegante "modalità scura":
body { display: flex; justify-content: center; align-items: center; background-color: #222; height: 100vh; }Con ciò, abbiamo creato un pulsante animato completamente funzionale utilizzando alcuni CSS di base e un breve snippet JavaScript. È facile modificare le trasformazioni che abbiamo applicato per creare una varietà di animazioni. I lettori possono semplicemente eseguire il fork di CodePen, che include un po' di CSS in più per lucidare, e diventare creativi.
Lavorare con i dati SVG da editor esterni
Il nostro menù hamburger è estremamente semplice. E se volessimo realizzare qualcosa di più complesso? È qui che la codifica manuale di SVG diventa difficile e il software di editing di grafica vettoriale può aiutare.
La nostra seconda animazione SVG è un pulsante muto che mostra l'icona di una cuffia. Quando la musica è attiva, l'icona pulsa e danzerà; quando è disattivato, l'icona sarà barrata:
Vedi il pulsante Pen Mute - 5 - barrato rosso di Filip Defar (@dabrorius) su CodePen.
Le icone di disegno non rientrano nell'ambito di questo tutorial (e probabilmente nella descrizione del tuo lavoro), quindi inizieremo con un'icona SVG pre-disegnata. Vorremo anche lo stesso stile del body del nostro esempio di menu di hamburger.
Potresti voler ripulire il codice SVG prima di lavorarci. Puoi farlo con svgo, uno strumento di ottimizzazione SVG basato su Node.js open source. Ciò rimuoverà gli elementi non necessari e renderà il codice più facile da modificare a mano, cosa che dovrai fare per aggiungere classi e combinare elementi diversi.
È improbabile che le icone SVG create nel software di modifica delle immagini utilizzino unità relative. Inoltre, vogliamo assicurarci che le proporzioni dell'icona siano mantenute, indipendentemente dalle proporzioni dell'elemento SVG che la contiene. Per rendere possibile questo livello di controllo, utilizzeremo l'attributo viewBox .
È una buona idea ridimensionare l'SVG in modo che viewBox possa essere impostato su alcuni valori facili da usare. In questo caso, l'ho convertito in un viewBox di 100 x 100 pixel.
Assicuriamoci che l'icona sia centrata e di dimensioni adeguate. Applicheremo la classe mute al nostro elemento SVG di base e quindi aggiungeremo i seguenti stili CSS:
.mute { fill: white; width: 80px; height: 70px; cursor: pointer; } Qui, la width è leggermente maggiore height per evitare il clipping durante le rotazioni della nostra animazione.
Il nostro punto di partenza per l'animazione SVG
L'SVG ora pulito contiene un singolo elemento <g> che contiene tre elementi <path> .
L'elemento percorso ci consente di disegnare linee, curve e archi. I percorsi sono descritti con una serie di comandi che descrivono come deve essere disegnata la forma. Poiché la nostra icona è composta da tre forme non collegate, abbiamo tre percorsi per descriverle.
L'elemento g SVG è un contenitore utilizzato per raggruppare altri elementi SVG. Lo usiamo per applicare le trasformazioni pulsanti e danzanti su tutti e tre i percorsi contemporaneamente.
<svg class="mute" viewBox="0 0 100 100"> <g> <path d="M92.6,50.075C92.213,26.775 73.25,7.938 50,7.938C26.75,7.938 7.775,26.775 7.388,50.075C3.112,51.363 -0.013,55.425 -0.013,60.25L-0.013,72.7C-0.013,78.55 4.575,83.3 10.238,83.3L18.363,83.3L18.363,51.6C18.4,51.338 18.438,51.075 18.438,50.813C18.438,33.275 32.6,19 50,19C67.4,19 81.563,33.275 81.563,50.813C81.563,51.088 81.6,51.338 81.638,51.6L81.638,83.313L89.763,83.313C95.413,83.313 100.013,78.563 100.013,72.713L100.013,60.263C100,55.438 96.875,51.362 92.6,50.075Z" /> <path d="M70.538,54.088L70.538,79.588C70.538,81.625 72.188,83.275 74.225,83.275L74.225,83.325L78.662,83.325L78.662,50.4L74.225,50.4C72.213,50.4 70.538,52.063 70.538,54.088Z" /> <path d="M25.75,50.4L21.313,50.4L21.313,83.325L25.75,83.325L25.75,83.275C27.788,83.275 29.438,81.625 29.438,79.588L29.438,54.088C29.45,52.063 27.775,50.4 25.75,50.4Z" /> </g> </svg> Per far pulsare e ballare le cuffie, la transition non sarà sufficiente. Questo è un esempio abbastanza complesso da richiedere fotogrammi chiave.
In questo caso, i nostri fotogrammi chiave iniziali e finali (rispettivamente allo 0% e al 100% dell'animazione) utilizzano un'icona delle cuffie leggermente rimpicciolita. Per il primo 40% dell'animazione ingrandiamo leggermente l'immagine e la incliniamo di 5 gradi. Quindi, per il successivo 40% dell'animazione, lo riduciamo a 0,9x e lo ruotiamo di 5 gradi sull'altro lato. Infine, per l'ultimo 20% dell'animazione, la trasformazione dell'icona torna agli stessi parametri iniziali per scorrere senza intoppi.
@keyframes pulse { 0% { transform: scale(0.9); } 40% { transform: scale(1) rotate(5deg); } 80% { transform: scale(1) rotate(-5deg); } 100% { transform: scale(0.9) rotate(0); } }Ottimizzazioni dell'animazione CSS
Per mostrare come funzionano i fotogrammi chiave, abbiamo lasciato il CSS dei fotogrammi chiave più dettagliato di quanto dovrebbe essere. Ci sono tre modi in cui potremmo accorciarlo.
Poiché il nostro fotogramma chiave 100% imposta l'intero elenco di transform , se dovessimo omettere completamente rotate() , il suo valore sarebbe predefinito su 0:
100% { transform: scale(0.9); } In secondo luogo, sappiamo che vogliamo che i nostri fotogrammi chiave 0% e 100% corrispondano perché stiamo riproducendo l'animazione in loop. Definendoli con la stessa regola CSS, non dovremo ricordarci di modificarli entrambi se vogliamo cambiare questo punto condiviso nel ciclo di animazione:
0%, 100% { transform: scale(0.9); } Infine, applicheremo presto transform: scale(0.9); alla classe mute__headphones , e quando lo faremo, non avremo bisogno di definire i fotogrammi chiave di inizio e fine! Per impostazione predefinita, utilizzeranno lo stile statico utilizzato da mute__headphones .
Ora che abbiamo definito i fotogrammi chiave dell'animazione, possiamo applicare l'animazione. Aggiungiamo la classe .mute__headphones <g> in modo che influisca su tutte e tre le parti dell'icona delle cuffie. Innanzitutto, impostiamo ancora una volta transform-origin al center poiché vogliamo che l'icona ruoti attorno al suo centro. Lo ridimensioniamo anche in modo che le sue dimensioni corrispondano al fotogramma chiave dell'animazione iniziale. Senza questo passaggio, il passaggio dall'icona statica "disattivata" a quella animata comporterà sempre un improvviso aumento delle dimensioni. (In ogni caso, il ritorno all'audio disattivato causerà un salto di scala, e probabilmente anche una rotazione, se l'utente fa clic mentre la scala è maggiore di 0,9x. Non possiamo fare molto per questo effetto solo con i CSS.)
Applichiamo l'animazione utilizzando la proprietà CSS animation ma solo quando è presente la classe genitore .is-active , in modo simile a come abbiamo animato il nostro menu hamburger.
.mute__headphones { transform-origin: center; transform: scale(0.9); } .is-active .mute__headphones { animation: pulse 2s infinite; }Il JavaScript di cui abbiamo bisogno per passare da uno stato all'altro segue lo stesso schema del menu dell'hamburger:
const muteButton = document.querySelector(".mute"); muteButton.addEventListener("click", () => { muteButton.classList.toggle("is-active"); }); Il prossimo pezzo che aggiungeremo è una linea barrata che appare quando l'icona è inattiva. Poiché si tratta di un semplice elemento di design, possiamo codificarlo manualmente. È qui che è utile avere valori viewBox semplici e ragionevoli. Sappiamo che i bordi della tela sono a 0 e 100, quindi è facile calcolare le posizioni di inizio e fine per la nostra linea:
<line x1="12" y1="12" x2="88" y2="88" class="mute__strikethrough" />Ridimensionamento e utilizzo di unità relative
È possibile creare un caso per l'utilizzo di unità relative invece di ridimensionare l'immagine. Questo vale nel nostro esempio perché stiamo aggiungendo solo una semplice linea SVG sulla nostra icona.
Negli scenari del mondo reale potresti voler combinare contenuti SVG più complessi provenienti da diverse fonti. È qui che è utile renderli tutti di una dimensione uniforme, poiché non possiamo codificare manualmente i valori relativi come abbiamo fatto nel nostro esempio.
Poiché abbiamo applicato una classe direttamente al nostro elemento barrato <line> , possiamo definirlo tramite CSS. Dobbiamo solo assicurarci che la linea non sia visibile quando l'icona è attiva:
.mute__strikethrough { stroke: red; opacity: 0.8; stroke-width: 12px; } .is-active .mute__strikethrough { opacity: 0; } Facoltativamente, possiamo aggiungere la classe .is-active direttamente all'SVG. Ciò farà iniziare l'animazione non appena la pagina viene caricata, quindi modifichiamo in modo efficace lo stato iniziale dell'icona da non animato (disattivato) ad animato (non disattivato).
L'animazione SVG basata su CSS è qui per restare
Abbiamo solo scalfito la superficie delle tecniche di animazione CSS e il funzionamento delle finestre. Vale la pena sapere come scrivere codice SVG a mano per mantenere semplici le animazioni semplici, ma è anche importante sapere come e quando utilizzare la grafica creata con editor esterni. Mentre i browser moderni ci consentono di creare animazioni impressionanti utilizzando solo funzionalità integrate, per casi d'uso (molto) complessi, gli sviluppatori potrebbero voler esplorare librerie di animazioni come GSAP o anime.js.
Le animazioni non devono essere riservate a progetti stravaganti. Le moderne tecniche di animazione CSS ci consentono di creare un'ampia gamma di animazioni accattivanti e raffinate in un modo semplice e compatibile con più browser.
Un ringraziamento speciale a Mike Zeballos per la recensione tecnica di questo articolo!
