Vai al contenuto
animorio
EN
Tutti i componenti

Il pulsante che ricompone la parola

Pulsanti, Testo, FisicaGSAP, Solo CSSImpegnativaPeso compresso: Demo 8,8 KBGSAP 28 KBGratisScarica lo zip

Il pulsante Add to bag di un negozio, nello stile minimal: una pillola nera con le lettere composte come caratteri mobili. Al clic la parola si ricompone in quella nuova lettera per lettera: le lettere in comune restano e scivolano al loro posto (la g di bag corre fino in fondo ad Adding), le altre escono e cadono dentro una dopo l’altra, mentre l’asse della larghezza del carattere tiene ogni parola vicina alla stessa misura e la pillola fa il resto su una molla. Poi Added to bag, con la spunta disegnata in vermiglio.

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>The button that recomposes the word</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the frame keeps the room of the widest word, so the preview never has to move -->
    <div class="frame" data-frame>
      <!-- the button: a black pill whose letters are movable type. Pressed, the word recomposes itself into the next
           one: the letters the two words share slide to their new place, the others leave and arrive one after the
           other, and the width axis of the typeface keeps every word near the same measure. The letters and the
           tick are laid out by the script on every frame -->
      <button class="bag" type="button" aria-label="Add to bag" data-bag data-autoclic>
        <span class="bag__pill" aria-hidden="true" data-pill>
          <span class="bag__line" data-line>
            <svg class="bag__tick" viewBox="0 0 20 20" data-tick><path d="M4.2 10.6l3.7 3.6 7.9-8.4" pathLength="1" data-tick-path/></svg>
          </span>
        </span>
      </button>
    </div>
    <p class="sr" role="status" aria-live="polite" data-said></p>
    <!-- a hidden copy of the type, to measure every letter at every width and weight -->
    <div class="ruler" aria-hidden="true" data-ruler></div>
  </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.

23 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 «Il pulsante che ricompone la parola» da Animorio e adattala al mio sito

Cosa fa

Su un fondo bianco c’è solo una pillola nera alta 60 pixel con scritto Add to bag in Mona Sans, chiaro su nero. All’apertura la pillola nasce tonda e le lettere entrano una dopo l’altra, ognuna nel suo posto che si apre. Al clic la parola diventa Adding: la A e le due d restano dove sono, «to ba» cade fuori dalla riga una lettera dopo l’altra mentre il suo posto si chiude, la g scivola a sinistra fino in fondo alla parola nuova, e la i e la n si aprono il loro posto e ci cadono dentro dall’alto: toccano la riga un pixel più in basso, tornano su e per un attimo prendono peso, come una lettera di piombo battuta nel compositoio. Adding è corta: le lettere si allargano sull’asse wdth per avvicinarsi alla misura della parola di prima, e quello che l’asse non copre lo prende la pillola, che si stringe su una molla smorzata con un filo di rimbalzo e intanto si abbassa di un pelo, come la gomma. Mentre il negozio lavora, un’onda di larghezza e di peso corre dentro Adding da sinistra a destra, una lettera dopo l’altra si gonfia e si alza di due pixel, e la pillola respira con lei. Poi Added to bag: la i e la n escono, arrivano «ed to ba», la g corre di nuovo in fondo, tutte le lettere si stringono fino a 78 sull’asse della larghezza per restare nella misura, davanti si apre il posto della spunta e la spunta si disegna in vermiglio. Dopo un momento escono solo la e e la d, la riga si richiude, le lettere si riallargano e torna Add to bag. Sotto il puntatore le lettere si allargano una dopo l’altra e la pillola si gonfia di qualche pixel; premendo si schiaccia, più larga e più bassa, e lasciando torna sulla molla.

Come funziona

Le lettere in comune

Per sapere quali lettere restano, lo script cerca la sottosequenza comune più lunga fra la parola di prima e quella nuova, con la tabella della programmazione dinamica, e la percorre dall’inizio prendendo sempre la coppia più a sinistra. Così fra Add to bag e Adding restano A, d, d e g, fra Added to bag e Add to bag restano tutte tranne la e e la d. Le lettere in comune non si incrociano mai, perché la sottosequenza tiene il loro ordine: fra due lettere che restano si mettono prima quelle che escono, poi quelle che entrano, e la riga è una sola fila di lettere in viaggio.

Il carattere misurato una volta

Mona Sans è un carattere variabile con l’asse della larghezza (da 75 a 125) e del peso. All’avvio un righello nascosto scrive ogni lettera delle tre parole a cinque larghezze e cinque pesi e ne misura l’avanzamento con getBoundingClientRect; l’avanzamento a una larghezza e a un peso qualsiasi si ricava interpolando fra i quattro valori vicini. Le lettere sono elementi separati, che perdono la crenatura: le coppie (Ad, to, ba…) si misurano su un canvas nello stesso carattere, ab meno a meno b, e si rimettono a mano.

La misura tenuta dall’asse

Per ogni parola lo script cerca per bisezione la larghezza dell’asse che la fa lunga MEASURE pixel, dentro AXIS: Add to bag sta poco sopra 100, Added to bag scende fino a 78. Adding è troppo corta per arrivarci, e si ferma prima del massimo per lasciare all’onda lo spazio di allargarsi. Ogni lettera che resta passa alla larghezza nuova mentre scivola, e quella che entra arriva già alla sua.

La riga composta a ogni fotogramma

Ogni lettera è un insieme di numeri che GSAP muove: larghezza, peso, altezza, trasparenza e presenza, cioè quanto è aperto il suo posto nella riga. A ogni fotogramma una funzione sul ticker di GSAP somma gli avanzamenti moltiplicati per la presenza, centra la riga e mette ogni lettera al suo posto con un translate3d e la sua font-variation-settings. Una lettera che esce chiude il suo posto e una che entra lo apre spingendo le vicine, senza salti; mentre entra o esce è larga quanto il suo posto (scaleX uguale alla presenza), così non copre mai le vicine. La g che corre in fondo non ha un’animazione sua: si sposta perché la riga si ricompone intorno a lei.

La pillola sulla molla

La larghezza della pillola è quella della riga più il margine, ma non la segue di colpo: è una molla smorzata (rigidezza e smorzamento in SPRING) integrata a mezzo passo, col passo di tempo limitato a 1/30 di secondo. Anche l’altezza ha la sua molla: 60 a riposo, un po’ di più sotto il puntatore, un po’ meno sotto il dito, e mentre la larghezza corre la pillola si abbassa di un pelo, al massimo 2,5 pixel. Quando molle e tween sono fermi il ticker si toglie da solo; ogni timeline lo risveglia dal suo onUpdate.

Gli stati e l’onda

Il clic passa ad Adding e mette il pulsante in aria-busy; dopo WAIT secondi viene Added to bag, dopo HOLD si torna ad Add to bag, e un clic durante il giro non fa niente. Un testo nascosto con role=status dice Adding to bag e Added to bag. L’onda di Adding è una campana che corre lungo la parola, ripetuta senza fine: ogni lettera si allarga di WAVE[0] e prende peso quando la campana le passa sopra; il cambio di parola la spegne in tre decimi di secondo.

Valori da cambiare

NomeFileDi partenzaCosa cambia
WORDSscript.js['Add to bag', 'Adding', 'Added to bag']Le tre parole: a riposo, mentre il negozio lavora, a cosa fatta (con la spunta davanti). Più lettere hanno in comune, più la ricomposizione è bella.
WAITscript.js2.2I secondi di Adding; in un negozio vero, il tempo che il carrello ci mette a rispondere.
HOLDscript.js1.8I secondi in cui resta Added to bag prima di tornare ad Add to bag.
MEASUREscript.js96La larghezza in pixel a cui l’asse del carattere prova a tenere ogni parola.
AXISscript.js[78, 125]Quanto possono stringersi e allargarsi le lettere per tenere la misura (Mona Sans va da 75 a 125).
WEIGHTscript.js[600, 780]Il peso delle lettere, e il peso che prende per un attimo una lettera quando tocca la riga.
MOVEscript.js0.75I secondi di una ricomposizione.
STAGGERscript.js0.045I secondi fra una lettera che entra e la successiva (quelle che escono vanno un po’ più svelte).
DROPscript.js15I pixel di cui cade una lettera che esce, e da cui cade una lettera che entra.
WAVEscript.js[30, 0.95]L’onda di Adding: di quanto si allarga una lettera quando l’onda le passa sopra, e i secondi di un passaggio.
SPRINGscript.js[520, 0.62]La molla della pillola: la rigidezza e lo smorzamento (sotto 1 va un po’ oltre e torna).
SWELLscript.js8I pixel di cui si gonfia la pillola sotto il puntatore.

Provali nel Playground

Quando usarla

Per il pulsante che mette un prodotto nel carrello, e in genere per ogni azione con un’attesa e un esito (Save, Saving, Saved; Send, Sending, Sent): funziona meglio quando le parole dei tre stati hanno molte lettere in comune. Serve un carattere variabile con l’asse della larghezza: con un carattere fisso le lettere si ricompongono lo stesso, ma la misura la tiene solo la pillola.

Sul telefono

La pillola è la stessa, alta 60, e sta comoda nei 390 pixel anche con Added to bag. Senza puntatore non c’è il gonfiarsi dell’hover: il tocco schiaccia la pillola e la rilascia sulla molla, e fa partire il giro intero, con le stesse animazioni del computer.

Con il movimento ridotto

Niente lettere che cadono o scivolano, niente onda e niente molla: a ogni cambio la riga sfuma, la parola nuova si compone al suo posto con la pillola già della misura giusta e la riga torna. Durante Adding la scritta pulsa piano di trasparenza, e la spunta compare già disegnata.

Trappole

  • Le lettere che entravano erano già intere quando il loro posto era aperto solo a metà, e coprivano le vicine; aspettando che il posto fosse aperto, invece, la riga mostrava un buco e si leggeva Add g. La soluzione è legare la larghezza della lettera che entra o esce alla sua presenza (scaleX uguale a p): la lettera è sempre larga quanto il suo posto, e diventa visibile mentre si allarga.
  • Con i posti nuovi che si aprivano prima che quelli vecchi si chiudessero, la g di bag andava prima a destra e poi a sinistra. Le lettere che escono partono subito e chiudono il posto in 0,6 volte MOVE; quelle che entrano partono dopo, così la lettera che resta va sempre nella stessa direzione.
  • Separando la parola in elementi la crenatura sparisce e le coppie perdono il loro spazio giusto: la misura calcolata non sarebbe più quella vera. Per questo le lettere hanno font-kerning: none e le coppie si misurano a parte su un canvas.
  • index.css di Fontsource carica solo l’asse del peso: senza wdth.css la font-variation-settings su wdth non fa niente e la misura resta tutta alla pillola.
  • Adding, troppo corta, si fermava a 125 e l’onda non aveva più spazio per allargare le lettere: per la parola dell’attesa la bisezione si ferma a 125 meno WAVE[0].
  • Un ticker che si spegne quando niente si muove non vede partire i tween in ritardo di una timeline: ogni timeline lo risveglia dal suo onUpdate, che GSAP chiama anche mentre aspetta.

Librerie

GSAP 3.15.0, Mona Sans (font variabile, con gli assi del peso e della larghezza) 5.3.0.

Compressi con gzip, i tre file della demo pesano 8,8 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