Sviluppo web

Animazioni con Tailwind senza JavaScript

Tailwind anima con transizioni e keyframes CSS: transition-*, duration-* e animate-*, nessun runtime. Le uscite restano la parte difficile.

In sintesi

  • Le classi transition-*, duration-* e animate-* compilano in transizioni e keyframes CSS, senza runtime nel browser.
  • In Tailwind 4 un'animazione nuova si dichiara nel tema con --animate-* e @keyframes nello stesso blocco.
  • Nessuno dei 97 blocchi shadcn/ui in cache usa animate-*: l'animazione resta una scelta manuale.

Tailwind CSS anima con il solo CSS: le classi transition-*, duration-* e animate-* compilano in transizioni e keyframes, quindi il browser non esegue JavaScript per far muovere un elemento.

Come si dichiara un'animazione

In Tailwind 4 il tema vive nel CSS: una variabile --animate-nome crea l'utility animate-nome, e i @keyframes stanno nello stesso blocco @theme. Non serve tailwind.config.js.

@import "tailwindcss";

@theme {
  --animate-slide-in: slide-in 240ms ease-out;

  @keyframes slide-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
  }
}

Dopo la build l'elemento usa class="animate-slide-in" e il browser applica i keyframes senza ascoltare eventi. La documentazione tailwindcss.com, letta il 1 novembre 2026, descrive --animate-* come namespace del tema.

npx @tailwindcss/cli -i ./src/input.css -o ./dist/output.css --watch

Il comando richiede Node e riscrive dist/output.css a ogni salvataggio; il file src/input.css deve iniziare con @import "tailwindcss";.

Transizioni di stato, non timeline

Per hover, focus e cambio di tema bastano transition-colors e duration-200: la proprietà cambia e il browser interpola. Per un ingresso legato a un attributo, come data-state="open", la variante data-[state=open]:animate-slide-in elimina il JavaScript di orchestrazione.

  • Una transizione CSS non blocca il thread principale e non aggiunge kilobyte di JavaScript.
  • Con motion-reduce:animate-none rispetti prefers-reduced-motion, ma il test manuale resta obbligatorio.
  • I 97 blocchi in cache non animano nulla per default: animate-* compare 0 volte.
  • Fonte: documentazione tailwindcss.com e licenza MIT del repository, lette il 1 novembre 2026.

Dove si rompe

L'uscita è la parte difficile: se il nodo esce dal DOM la transizione non parte. Servono transition-behavior: allow-discrete e @starting-style, oppure un listener transitionend che smonta il nodo dopo l'ultimo frame. Tailwind non orchestra sequenze e non ritarda lo smontaggio: quella decisione resta del componente.

Dove continuare

Nel catalogo EneUI trovi typewriter, typing-animation e marquee along an SVG path, tutti costruiti con classi Tailwind. La definizione del framework è in che cos'è Tailwind CSS; il confronto tra librerie è in migliori librerie di animazione; il confronto tra approcci CSS è in Tailwind contro CSS modules. Gli altri due pezzi della serie sono focus-visible con Tailwind e stili di stampa con Tailwind.

Domande frequenti

Serve JavaScript per animare con Tailwind?

No. Le classi compilano in transizioni e keyframes CSS, che il browser esegue da solo. Il JavaScript che scrivi resta quello del componente, non dell'animazione.

Qual è la differenza tra transition-* e animate-*?

transition-* interpola un cambio di proprietà già avvenuto, per esempio su hover. animate-* esegue keyframes una volta o in loop, indipendentemente dal cambio di stato.

Come si aggiunge un'animazione personalizzata?

Dichiari --animate-nome nel blocco @theme e scrivi i @keyframes nello stesso blocco. La build genera l'utility animate-nome, che usi come le altre classi.

Tailwind rispetta prefers-reduced-motion?

Sì, con la variante motion-reduce, per esempio motion-reduce:animate-none. Il tema non la applica da solo: va scritta su ogni elemento animato.

Perché la mia animazione non parte?

Di solito il nodo esce dal DOM prima della fine della transizione, oppure la classe viene costruita a runtime e non arriva al file CSS. Controlli la classe nel file generato e il momento in cui il nodo viene smontato.