Vai al contenuto
animorio
EN
Tutti i componenti

I passi con la linea che avanza

Passi, Transizioni, Fisica, SVGGSAPImpegnativaPeso compresso: Demo 9,3 KBGSAP 28 KBGratisScarica lo zip

I quattro passi di un acquisto, Cart, Shipping, Payment e Review, sopra una linea sottile: andando avanti la testa della linea corre al passo dopo nel colore d’accento e l’inchiostro la raggiunge un attimo dopo su una molla, tornando indietro la linea si riavvolge. Dove l’inchiostro arriva la linea vibra di un pixel fra due tacche, come una corda; il passo fatto si sposta, prende peso e si disegna la sua spunta. Stile minimal.

Il codice

Una cartella che funziona da sola: index.html, style.css, script.js e le librerie da CDN. Nelle schede React e Vue la stessa demo è già un componente, che spegne le sue animazioni quando esce dalla pagina.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Steps with the advancing line</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the checkout steps: one thin line under four names. Going on, the head of the line runs to the next tick and
         the tail catches it up on a spring; going back, the line winds itself in. The steps done take weight and a
         tick drawn by hand, the current one has its name in the accent -->
    <section class="flow" aria-label="Checkout" data-flow>
      <ol class="flow__steps" data-steps>
        <li class="step" data-step><button class="step__btn" type="button"><span class="step__lift"><svg class="step__check" viewBox="0 0 14 12" aria-hidden="true"><path d="M1.6 6.6l3.5 3.4 7.3-8.2"/></svg><span class="step__name">Cart</span></span></button></li>
        <li class="step" data-step><button class="step__btn" type="button"><span class="step__lift"><svg class="step__check" viewBox="0 0 14 12" aria-hidden="true"><path d="M1.6 6.6l3.5 3.4 7.3-8.2"/></svg><span class="step__name">Shipping</span></span></button></li>
        <li class="step" data-step><button class="step__btn" type="button"><span class="step__lift"><svg class="step__check" viewBox="0 0 14 12" aria-hidden="true"><path d="M1.6 6.6l3.5 3.4 7.3-8.2"/></svg><span class="step__name">Payment</span></span></button></li>
        <li class="step" data-step><button class="step__btn" type="button"><span class="step__lift"><svg class="step__check" viewBox="0 0 14 12" aria-hidden="true"><path d="M1.6 6.6l3.5 3.4 7.3-8.2"/></svg><span class="step__name">Review</span></span></button></li>
      </ol>

      <!-- the line: a faint track, the ink of the steps done and, in the accent, the stretch that is moving.
           The three share one path, cut by two clip rectangles; the script draws them -->
      <svg class="flow__line" aria-hidden="true" data-line>
        <defs>
          <clipPath id="flow-track"><rect data-clip="track" x="0" y="-20" width="0" height="60"/></clipPath>
          <clipPath id="flow-ink"><rect data-clip="ink" x="0" y="-20" width="0" height="60"/></clipPath>
          <clipPath id="flow-run"><rect data-clip="run" x="0" y="-20" width="0" height="60"/></clipPath>
        </defs>
        <path class="line__track" clip-path="url(#flow-track)" data-path/>
        <path class="line__ink" clip-path="url(#flow-ink)" data-path/>
        <path class="line__run" clip-path="url(#flow-run)" data-path/>
        <g data-ticks></g>
      </svg>

      <div class="flow__foot">
        <p class="flow__note" aria-live="polite" data-note><span class="roll__item">Two items in your bag</span></p>
        <div class="flow__actions">
          <button class="back" type="button" data-back>
            <svg class="back__arrow" viewBox="0 0 16 14" aria-hidden="true"><path d="M15 7H1.5M7 1.5L1.5 7 7 12.5"/></svg>
            <span class="back__text">Back</span>
          </button>
          <button class="next" type="button" data-next data-autoclic>
            <span class="next__body" aria-hidden="true"></span>
            <span class="next__text" data-next-text><span class="roll__item">Continue</span></span>
            <svg class="next__arrow" viewBox="0 0 16 14" aria-hidden="true"><path d="M1 7h13.5M9 1.5L14.5 7 9 12.5"/></svg>
          </button>
        </div>
      </div>
    </section>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Cambia valori, colori e testi con le manopole e guarda l’animazione rispondere dal vivo. Oppure scrivi tu nel codice. Poi scarica la cartella con le tue modifiche.

35 valori da cambiare

Oppure chiedila a Claude Code

Col connettore di Animorio, Claude Code la prende da qui con tutta la sua guida e la adatta al tuo progetto. Incolla questa richiesta:

Prendi «I passi con la linea che avanza» da Animorio e adattala al mio sito

Cosa fa

Su un fondo bianco quattro nomi in Archivo, Cart, Shipping, Payment e Review, ognuno all’inizio della sua colonna, e sotto una linea grigia sottilissima con una tacca all’inizio di ogni passo e una alla fine. Il passo in corso ha il nome e la tacca blu; quelli da fare sono grigi e leggeri. Sotto, a sinistra, una riga che dice cosa c’è in quel passo (Two items in your bag, Delivery in 2 to 4 working days…), a destra Back e un pulsante nero a pillola, Continue. Premendo Continue la testa della linea parte subito e corre fino alla tacca dopo in blu, mentre l’inchiostro nero la segue un attimo dopo su una molla più morbida: per un momento la linea è un tratto blu lungo, che l’inchiostro accorcia arrivando. Quando l’inchiostro passa la metà del passo il nome si scosta a destra, diventa nero e pesante e al suo posto si disegna una spunta; il nome del passo raggiunto è già blu. Dove l’inchiostro si posa la linea vibra fra le due tacche, un pixel o due, e i tratti vicini la sentono appena. Back fa il contrario: la testa torna indietro per prima e la coda la segue, la spunta si cancella, il nome perde peso e torna grigio. All’ultimo passo il pulsante dice Place order: l’inchiostro corre fino alla tacca della fine, tutta la linea vibra e il pulsante diventa Keep shopping, che riavvolge la linea fino al primo passo. Le parole del pulsante e della riga rotolano, e la pillola prende la larghezza delle parole nuove. Un passo fatto è un pulsante che riporta indietro fino a lui: col puntatore sopra il nome si allarga e si tinge di blu.

Come funziona

La linea in passi, non in pixel

La testa e la coda della linea sono due numeri in passi: 0 è la prima tacca, 4 la fine. I pixel si calcolano a ogni fotogramma dalla larghezza della linea, quindi cambiando la finestra a metà corsa le molle non se ne accorgono. La linea è un solo path SVG disegnato tre volte: la traccia grigia, l’inchiostro e il tratto blu, ognuno tagliato da un clipPath con un rettangolo, da 0 al più piccolo dei due numeri l’inchiostro, fra i due il blu.

Due molle legate

La testa va verso il passo scelto su una molla rigida, HEAD_SPRING; la coda non guarda il passo, guarda la testa, con una molla più morbida, TAIL_SPRING. E la testa sente la coda: finché la linea è tirata, una parte PULL della forza della coda la trattiene. Le due molle si integrano insieme a passi di 1/240 di secondo, col passo del fotogramma limitato a 1/30: così la testa arriva senza strappi, la coda la raggiunge, va di un pixel oltre e torna.

Tutto viene dalla linea

Nomi, tacche e spunte non hanno animazioni loro: a ogni fotogramma si calcolano da dove sono testa e coda, con smoothstep. Quanto un passo è fatto dipende dall’inchiostro fra metà e fine della sua colonna; quanto è in corso, dalla testa che arriva alla sua tacca. Da questi due numeri vengono il peso e la larghezza del carattere variabile (font-variation-settings), lo spostamento del nome, la spunta (stroke-dashoffset) e il colore, mescolato in CSS con color-mix fra grigio, blu e nero. Per questo tornando indietro tutto si disfa da sé, nello stesso ordine al contrario.

La corda fra due tacche

Ogni tratto fra due tacche è un piccolo oscillatore smorzato, undici volte al secondo. Quando la coda arriva alla tacca che cercava, il tratto appena riempito (o appena svuotato, tornando indietro) riceve un colpo che cresce con la strada fatta, i vicini la metà e meno. Il path si ridisegna allora con mezza sinusoide fra le due tacche e un poco della successiva; quando tutto è fermo torna una riga dritta e il ciclo si spegne.

Pulsanti, parole e tasti

Le parole della riga e del pulsante rotolano: la vecchia esce in alto e svanisce, la nuova sale un attimo dopo. La pillola prende la larghezza delle parole nuove con back.out quando cresce e senza rimbalzo quando si stringe, e un ResizeObserver la tiene giusta mentre l’asse wdth si allarga in hover. I passi fatti sono pulsanti col loro aria-label, quello in corso ha aria-current="step", Back resta raggiungibile con aria-disabled; le frecce destra e sinistra vanno avanti e indietro.

Il giro dell’anteprima

Un clic fatto da uno script (isTrusted falso, quello dell’anteprima) non fa un passo ma avvia una timeline GSAP che mostra tutti gli stati: due passi avanti, uno indietro, di nuovo avanti fino all’ultimo, l’ordine fatto e il riavvolgimento fino al primo passo. Un clic vero, un tocco o un tasto la fermano dove si trova.

Valori da cambiare

NomeFileDi partenzaCosa cambia
NOTESscript.js['Two items in your bag', …]La riga sotto i passi: una per passo e una in più per l’ordine fatto.
ACTIONSscript.js['Continue', 'Place order', 'Keep shopping']Le parole del pulsante: lungo la strada, all’ultimo passo e a ordine fatto.
HEAD_SPRINGscript.js[700, 0.85]La molla della testa della linea: quanto è rigida e quanto è smorzata (1 vuol dire senza andare oltre).
TAIL_SPRINGscript.js[130, 0.8]La molla della coda, tirata dalla testa: quanto è rigida e quanto è smorzata. Più morbida, più la linea si allunga.
PULLscript.js0.25Quanto la coda trattiene la testa mentre la linea è tirata (da 0 a 1).
PLUCKscript.js2Di quanti pixel vibra la linea fra due tacche dove arriva la coda.
WEIGHTscript.js[360, 540, 680]Il peso di un nome: un passo da fare, il passo in corso, un passo fatto (da 100 a 900).
WIDTHscript.js[96, 106, 100]La larghezza del carattere (asse wdth) negli stessi tre casi (da 62 a 125).

Provali nel Playground

Quando usarla

Per il checkout di un negozio online, per una prenotazione, un’iscrizione o un modulo lungo diviso in tre, quattro o cinque passi: dove serve dire con calma a che punto si è, senza icone né cerchi, e far sentire il passo avanti come una cosa fatta.

Sul telefono

Le stesse animazioni a misure adattate: i quattro passi restano in fila sulla larghezza dello schermo, coi nomi un po’ più piccoli; la riga va sopra e i due pulsanti sotto, Back a sinistra e la pillola a destra. Col tocco si va avanti, indietro e si torna a un passo fatto toccandolo.

Con il movimento ridotto

Niente molle, niente corsa e niente vibrazione: la linea, i nomi e le spunte sono subito al loro posto nuovo, e passi e linea ricompaiono con una breve dissolvenza; le parole della riga e del pulsante cambiano in dissolvenza invece di rotolare. All’apertura tutto compare in dissolvenza.

Trappole

  • Il colpo sulla corda preso dalla velocità della coda all’arrivo era quasi zero (un quinto di pixel), perché una molla arriva piano: il colpo cresce con la strada fatta, e così si vede.
  • Tornando indietro di tre passi i nomi in mezzo diventavano blu tutti insieme, perché l’accento seguiva il punto più lontano della linea: ora segue solo la testa, e i passi che lascia tornano grigi.
  • La pillola che si stringeva con back.out andava per un attimo sotto la larghezza delle parole e le tagliava: si allarga col rimbalzo, si stringe senza, e solo quando la parola vecchia è uscita.
  • Le due righe che rotolavano insieme, una sopra l’altra, si vedevano per metà tutte e due nello stesso istante: la vecchia esce in fretta e svanisce, la nuova sale un attimo dopo.
  • All’apertura le tacche spuntavano prima che la traccia arrivasse a loro: ognuna ora parte quando la traccia la raggiunge.
  • Sul telefono la riga sotto i passi spariva: col piede in colonna, flex: 1 le dava altezza zero. Lì ha flex: none.

Librerie

GSAP 3.15.0, Archivo (font variabile) 5.3.0.

Compressi con gzip, i tre file della demo pesano 9,3 KB; le librerie: GSAP 28 KB.

Collaudo

Provata il 16 ottobre 2026

  • Computer: Fatto
  • Telefono: Fatto
  • Movimento ridotto: Fatto
  • Safari su iPhone: Da fare

Licenza d’uso

Puoi usarla nei tuoi progetti e in quelli dei tuoi clienti. Non puoi rivenderla né ridistribuirla così com’è. GSAP resta sotto la sua licenza Standard. Licenza completa.

Tutti i componenti