
✨ Animare linee SVG e percorsi chiusi con puro CSS
L'animazione del tratto SVG è una di quelle tecniche che trasforma un'icona statica in un'illustrazione viva. Avrai già visto questo effetto: il contorno di un logo si disegna da solo in modo fluido, come se una penna invisibile tracciasse la forma dall'inizio alla fine. Sembra costoso, ma si realizza con puro CSS.
Il problema è che la maggior parte dei tutorial si ferma al caso più semplice: un percorso aperto, una singola linea, animazione dall'inizio alla fine. Ma la grafica reale è fatta di contorni chiusi, forme spezzate e direzioni di disegno che il designer non ha controllato. Un tracciato SVG può iniziare in qualsiasi punto, e tu hai bisogno che si disegni in senso orario partendo da un punto di partenza esteticamente gradevole.
Qui sotto trovi la serie completa di tecniche: dall'animazione base alle doppie linee e al pieno controllo sui punti di inizio e fine. Tutto in puro CSS, senza librerie né misurazioni a runtime. Questi metodi sono stati testati durante lo sviluppo del plugin SVG Divider e funzionano in qualsiasi browser moderno.
💡 Panoramica rapida:
- Trova la lunghezza del tracciato SVG tramite
getTotalLength()o Illustrator e scrivi il numero nel CSS. - Imposta
stroke-dasharray: LENGTHe animastroke-dashoffsetdaLENGTHa0. - Per invertire la direzione, scambia tratto e spazio in
stroke-dasharraye sposta in avantistroke-dashoffset. - Sposta il punto di partenza aggiungendo metà (o una qualsiasi frazione) della lunghezza a
stroke-dashoffset. - Avvia l'animazione "inside-out": parti da
HALF_LENGTH, arriva aFULL_LENGTH. - Imposta le doppie linee tramite
stroke-dasharraya metà lunghezza estroke-dashoffsetspostato di un quarto.
Fondamenti tecnici: tratti, spazi e lunghezza del tracciato
Alla base di qualsiasi animazione SVG ci sono due proprietà CSS: stroke-dasharray e stroke-dashoffset. La prima definisce un pattern "tratto-spazio" lungo il contorno, la seconda sposta questo pattern. Se rendi il tratto uguale alla lunghezza totale del tracciato e poi animi l'offset, la linea si "disegna" davanti ai tuoi occhi.
Il passaggio chiave prima di qualsiasi animazione è trovare la lunghezza totale del tracciato. Metodi:
- JavaScript:
document.querySelector('path').getTotalLength(), una chiamata da console, il numero va scritto direttamente nel CSS. Nessun runtime. - Illustrator: il pannello "Informazioni documento" mostra la lunghezza del tracciato selezionato.
- Script personalizzato: se hai decine o centinaia di tracciati, ha senso scrivere un'attraversamento automatico e la marcatura delle lunghezze.
Sfumatura importante: getTotalLength() e Illustrator possono dare numeri leggermente diversi per lo stesso tracciato. Il motivo è la diversa precisione di calcolo. La discrepanza è di solito entro 1-2 unità e non influisce sulla resa visiva.
Controlla la geometria del tracciato per eventuali errori. La direzione di disegno e il punto di partenza dipendono da come il designer ha costruito la curva nell'editor, è normale. Più avanti impareremo a controllare entrambi senza modificare l'SVG stesso.
Animazione base: disegnare una linea dall'inizio alla fine
Caso più semplice: un tracciato aperto con una lunghezza di, diciamo, 100 unità. Imposta il tratto alla lunghezza totale e anima l'offset da 100 a 0:
1 @keyframes reveal { 2 to { 3 stroke-dashoffset: 0; 4 } 5 } 6 svg path { 7 stroke-dashoffset: 100; 8 stroke-dasharray: 100; 9 animation: reveal 1s ease-in-out 0s forwards; 10 }
Cosa succede qui: stroke-dasharray: 100 imposta 100 unità di linea piena e 100 unità di spazio vuoto (il secondo valore è uguale al primo per impostazione predefinita). stroke-dashoffset: 100 sposta il pattern in modo che la parte visibile vada oltre i confini del tracciato, la linea è invisibile. L'animazione riduce l'offset a zero e il tratto si materializza nella sua posizione.
Alcune note pratiche:
- Sostituisci
FULL_LENGTHcon il numero effettivo senza unità di misura. Il motore CSS non capiscepxoemall'interno distroke-dasharray. - Il selettore
svg pathè per un solo contorno. Se l'SVG ha più tracciati, usa classi, ID o pseudo-classi comepath:nth-of-type(3). Strumenti di debug::nth Testere nthmaster.com. - Il nome di
@keyframesdeve essere unico per ogni variante di animazione. Tracciati diversi spesso richiedono keyframe propri. - Evita valori negativi di
stroke-dashoffset: Safari può mostrare sfarfallii o artefatti con offset negativi.
Controllare la direzione: invertire il disegno
Per impostazione predefinita, l'animazione va dall'inizio alla fine del tracciato, ovunque il designer abbia disegnato la curva. Ma spesso serve l'opposto: un contorno chiuso che si disegna in senso orario anziché antiorario.
La soluzione è invertire il pattern del tratto: la linea inizia invisibile (0 tratto, 100 spazio) e diventa visibile (100 tratto, 0 spazio), mentre l'offset la tira indietro:
1 @keyframes reversed { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 0; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 100; 9 } 10 } 11 svg path { 12 animation: reversed 1s ease-in-out 0s forwards; 13 }
Il meccanismo funziona grazie alla natura ciclica del pattern del tratto: la linea piena si materializza alla fine del tracciato, mentre la sua copia va a sinistra oltre l'inizio e rimane invisibile. Lo stesso accade sui contorni chiusi: la copia del tratto appare "prima" dell'inizio e non interferisce con la percezione.
Esiste un approccio alternativo, più breve e senza manipolazione dell'array:
1 @keyframes alternative-reversed { 2 from { 3 stroke-dashoffset: 100; 4 } 5 to { 6 stroke-dashoffset: 200; 7 } 8 } 9 svg path { 10 stroke-dasharray: 100; 11 animation: alternative-reversed 1s ease-in-out 0s forwards; 12 }
Qui stroke-dasharray è fissato alla lunghezza totale, mentre l'offset va da 100 a 200. Stesso risultato, la linea si disegna in direzione inversa. Usa la variante che ti sembra più intuitiva.
Spostare il punto di partenza
Un tracciato chiuso è come una ferrovia circolare: il treno può partire da qualsiasi stazione. Il compito è spostare l'inizio dell'animazione in un punto esteticamente gradevole senza toccare la geometria stessa.
Partire dal lato opposto
Per contorni simmetrici, basta un offset di metà lunghezza:
1 @keyframes start-from-other-side { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 50; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 50; 9 } 10 } 11 svg path { 12 animation: start-from-other-side 1s ease-in-out 0s forwards; 13 }
La direzione di disegno resta quella originale, ma visivamente l'animazione parte dall'estremità opposta.
Invertire la direzione e punto di partenza arbitrario
Per invertire simultaneamente la direzione e spostare il punto di partenza, aggiungi la lunghezza totale all'offset finale:
1 @keyframes other-side-and-reverse { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 50; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 150; 9 } 10 } 11 svg path { 12 animation: other-side-and-reverse 1s ease-in-out 0s forwards; 13 }
Per un punto completamente arbitrario, sostituisci un valore qualsiasi al posto di 50. Prove ed errori (più o meno 5-10 unità) trovano la posizione ottimale. In un progetto, il punto di partenza su un'icona di bit di Twitch è stato spostato di 17 pixel, un numero brutto ma visivamente perfetto.
Animazione "inside-out"
La linea cresce dal centro in entrambe le direzioni simultaneamente, una tecnica classica per loghi e infografiche:
1 @keyframes inside-out { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 50; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 100; 9 } 10 } 11 svg path { 12 animation: inside-out 1s ease-in-out 0s forwards; 13 }
L'offset parte da metà lunghezza (centro del tracciato) e arriva alla lunghezza totale, trascinando il tratto con sé. Per forme asimmetriche, il punto di partenza può essere ulteriormente spostato:
1 @keyframes custom-inside-out { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 84; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 134; 9 } 10 }
Qui 84 = METÀ_LUNGHEZZA + 34. La costante 34 è scelta a mano per una forma specifica. Non esiste una ricetta universale: prova, guarda, regola.
Animazione "outside-in": doppia penna
L'approccio opposto: la linea si disegna da entrambe le estremità simultaneamente, convergendo verso il centro. Su contorni aperti questo dà un effetto "due penne":
1 @keyframes outside-in { 2 from { 3 stroke-dasharray: 0 100; 4 } 5 to { 6 stroke-dasharray: 50 0; 7 } 8 } 9 svg path { 10 animation: outside-in 1s ease-in-out 0s forwards; 11 }
Il tratto copre solo metà della lunghezza, il gap collassa due volte più velocemente che nell'animazione base. Qui stroke-dashoffset non serve: il pattern "0 gap" nello stato finale fa convergere da solo entrambe le metà del tratto.
Controllo totale: punti di inizio e fine
Quando una sola direzione e un solo punto di partenza non bastano, puoi controllare entrambi i confini del disegno. Due teste di linea in movimento convergono verso una destinazione comune:
1 @keyframes custom-start-end { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 30; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 80; 9 } 10 } 11 svg path { 12 animation: custom-start-end 1s ease-in-out 0s forwards; 13 }
I valori 30 e 80 sono arbitrari; l'unica regola fissa è che l'offset from sia minore dell'offset to. Se i punti sono vicini, un segmento vola veloce, l'altro striscia lentamente: è normale e persino bello.
Non aver paura di superare la lunghezza totale nel valore to. stroke-dashoffset: 130 con lunghezza 100 è legale, semplicemente sposta il ciclo del tratto al secondo giro. L'importante è evitare valori negativi.
Linee doppie ed effetti speciali
La modalità più flessibile: tratti a metà lunghezza con spostamento di un quarto. Ogni tracciato ottiene due teste di linea che si muovono indipendentemente:
1 @keyframes double-lines { 2 from { 3 stroke-dasharray: 0 50; 4 stroke-dashoffset: 25; 5 } 6 to { 7 stroke-dasharray: 50 0; 8 stroke-dashoffset: 50; 9 } 10 } 11 svg path { 12 animation: double-lines 1s ease-in-out 0s forwards; 13 }
Per forme complesse, l'array del tratto può essere composto da più componenti. La somma di tutti i valori dell'array deve essere uguale alla lunghezza totale. Esempio reale per un segno di infinito:
1 @keyframes infinity-double-lines { 2 from { 3 stroke-dasharray: 0 53 0 47; 4 stroke-dashoffset: 37; 5 } 6 to { 7 stroke-dasharray: 53 0 47 0; 8 stroke-dashoffset: 60; 9 } 10 } 11 svg .infinity { 12 animation: infinity-double-lines 8s ease-in-out 0s alternate infinite; 13 stroke: #8D69D8; 14 }
Quattro componenti dell'array (53 + 47 = 100 = lunghezza totale) si scambiano di posto tra from e to. L'animazione è in loop (infinite) e inverte la direzione (alternate), creando un contorno meditativo e pulsante che non si ripete mai in modo identico.
Video: animazione SVG in pratica
Per vedere dal vivo tutte le tecniche descritte e capire le sfumature di configurazione, guarda questo tutorial in inglese:
L'autore mostra passo passo la creazione di un'illustrazione SVG animata, dall'esportazione da Figma ai ritocchi finali in CSS. I timecode nella descrizione ti permettono di saltare direttamente alla sezione che ti serve.
⁉️🤔 Domande frequenti
Perché conoscere in anticipo la lunghezza del tracciato se esiste getTotalLength()?
getTotalLength()è JavaScript, e il nostro obiettivo è CSS puro senza dipendenze a runtime. Misuri la lunghezza UNA VOLTA (in console o in Illustrator), inserisci il numero direttamente nel CSS e l'animazione funziona senza una sola riga di JS.
Si possono animare più tracciati con una sola animazione?
Sì, se hanno la stessa lunghezza e lo stesso comportamento desiderato. Nella pratica i tracciati raramente coincidono, è più semplice dare a ciascuno i propri
@keyframeso usare variabili CSS con valori di lunghezza diversi.
Perché Safari sfarfalla con stroke-dashoffset negativo?
È un bug noto del rendering WebKit: i valori di offset negativi a volte vengono interpretati come un azzeramento istantaneo. La soluzione è mantenere sempre
stroke-dashoffset≥ 0; se ti serve uno spostamento, aggiungi la lunghezza intera invece di andare in negativo.
Cosa fare se l'animazione "scatta" all'inizio o alla fine?
Aggiungi
forwardsaanimation(mantiene lo stato finale) e rimuovialternatese non ti serve l'inversione. Verifica anche eventuali conflitti con altre regole CSS per lo stesso elemento, ad esempio unatransitionsulla stessa proprietà.
Funziona con stroke-dasharray su contorni chiusi con geometria complessa?
Sì, la meccanica è la stessa per qualsiasi tracciato SVG, linee rette, curve di Bézier, poligoni chiusi. L'unica differenza è che su un contorno chiuso non c'è un "inizio" e una "fine" visivi, quindi controllare il punto di partenza è particolarmente importante per l'estetica.
Vale la pena scrivere l'animazione a mano quando esistono le librerie?
Risposta breve: dipende dalla scala. Per un'icona una tantum su una landing page, il controllo manuale dà risultati perfetti senza dipendenze extra. Quindici minuti per regolare un offset, e il contorno si disegna esattamente come lo avevi pensato, non come ha deciso lo sviluppatore della libreria.
Quando abbiamo realizzato i divisori SVG per Elementor, il controllo manuale ha ripagato tre volte tanto. Il plugin usa decine di divisori animati, ciascuno con tratti regolati individualmente. Nessuna libreria darebbe un tale controllo sull'estetica.
Oltre alle tecniche di questo articolo, puoi sovrapporre:
- Controllo dello stato dell'animazione via JavaScript (avvio/stop/riavvio);
- Avvio lazy tramite
Intersection Observer, il contorno si disegna solo quando entra nel viewport; - Catene di animazioni tramite
animation-delay; - Funzioni di easing personalizzate (
cubic-bezier()); - Lavoro aggiuntivo sull'opacità nei
@keyframes; - Animazione elastica delle linee tratteggiate ("formiche che marciano").
Prendi gli schemi di questo articolo come base, sostituisci i tuoi valori di lunghezza e sperimenta con cubic-bezier(). Una funzione di easing scelta bene cambia la percezione dell'animazione più di quanto farebbe spostare il punto di partenza di un paio di pixel.



