È uscito il Corso Java Completo
Torna al blog

Tailwind o CSS classico: quale conviene

Tailwind o CSS classico: confronto onesto tra fogli di stile, classi di utilità, CSS Modules e variabili native, con tabella e verdetto per ogni caso d'uso.

Edoardo Midali

Edoardo Midali

Developer · Content Creator

10 min di lettura

La discussione va avanti da anni e si è incartata su due posizioni entrambe poco utili: "l'HTML diventa illeggibile" da una parte, "chi scrive ancora CSS a mano" dall'altra. Nessuna delle due risponde alla domanda che hai davvero, che è quale dei due conviene al tuo progetto. In questo articolo trovi la differenza di fondo tra i due approcci, i problemi reali del CSS su progetti grandi, cosa Tailwind peggiora, le alternative che quasi nessuno considera e un verdetto per caso d'uso.

Se non sai ancora cosa siano le classi di utilità, il punto di partenza è cos'è Tailwind CSS. Qui do per scontato che tu lo sappia e mi occupo solo del confronto.

La differenza di fondo

La differenza non è sintattica: è dove vive la decisione su come appare una cosa. Nel CSS classico sta in un foglio di stile, e l'HTML si limita a dichiarare cosa un elemento è. Con le utilità sta nel markup, e la distinzione tra "cos'è" e "come appare" scompare.

Da qui discende tutto il resto. Nel primo modello puoi cambiare l'aspetto di tutto il sito toccando un file, e il costo è che quel file è globale e nessuno sa chi dipende da cosa. Nel secondo l'aspetto è locale e visibile dove lo usi, e il costo è che non hai più un punto unico dove cambiare le cose e l'HTML diventa affollato.

Non è un dibattito su quale sia più elegante. È uno scambio tra due proprietà che non puoi avere insieme: un punto di controllo centralizzato, oppure la certezza di cosa tocchi quando modifichi qualcosa.

I problemi veri del CSS classico

Vale la pena elencarli con precisione, perché chi difende il CSS classico spesso non li ha vissuti su un progetto abbastanza grande, e chi lo attacca li esagera.

I nomi. BEM, SMACSS e le convenzioni interne sono tentativi seri su un problema senza soluzione pulita. Quel blocco è un card-header, un card-top o un card-title-wrapper? Ci passi minuti veri, ripetutamente, e non produce nulla per chi visita il sito.

La specificità e la cascata. Una regola non si applica e non capisci perché. Cerchi, e c'è un selettore con tre livelli che vince. Aggiungi un livello anche tu, e hai contribuito al problema. Dopo due anni di questo, qualcuno mette !important e la gara finisce così.

Nessuno sa se può cancellare una regola. È il problema peggiore. Trovi .product-card-header--compact in un file di quattromila righe: per cancellarla dovresti cercare quella stringa in ogni template, ogni componente, ogni email, ogni contenuto generato dinamicamente. Non ne hai la certezza, quindi non la cancelli. E così il CSS di un progetto cresce sempre e non cala mai.

La distanza tra codice e stile. Modifichi un componente e devi ricordarti quale file di stile toccare. Il markup è in un file, l'hover trenta righe più giù, la variante per tablet in una media query in fondo. Per ricostruire il comportamento di un elemento salti avanti e indietro.

Questi problemi, va detto, compaiono su una certa scala. Su un sito di cinque pagine non esistono. È per questo che la discussione è così polarizzata: le due parti stanno guardando progetti diversi.

Cosa risolve Tailwind e cosa peggiora

Cosa risolve, concretamente:

  • Niente nomi da inventare, perché non ci sono classi semantiche.
  • Niente guerre di specificità: le utilità hanno tutte lo stesso peso.
  • Il CSS non cresce: il set di utilità è finito, la centesima pagina riusa quelle esistenti.
  • Cancellare un componente cancella il suo stile, perché lo stile sta dentro di lui.
  • La scala di valori predefinita elimina le micro-decisioni da 13, 14 e 15 pixel.

Cosa peggiora, senza giri di parole:

  • L'HTML diventa verboso. Un div con quattordici classi è oggettivamente più difficile da leggere di uno con class="card". Chi dice il contrario sta difendendo una squadra.
  • La revisione del codice ne soffre. Una modifica allo stile appare come una riga lunghissima modificata, e capire cosa è cambiato richiede attenzione.
  • C'è una curva iniziale. Devi imparare i nomi, e ti serve comunque conoscere il CSS sotto: flexbox, grid, il box model. Non è una scorciatoia per chi non sa il CSS.
  • Dipendi da uno strumento di build. Serve una pipeline che analizzi i sorgenti e generi il file finale. Su un progetto senza build, è un costo introdotto dal nulla.
  • Il markup condiviso si lega allo strumento. Se domani cambi approccio, non porti via l'HTML così com'è.

Le alternative che spesso non si considerano

La discussione viene quasi sempre posta come binaria, e non lo è. In mezzo ci sono tre cose che risolvono buona parte dei problemi storici.

CSS Modules

Scrivi CSS normale, ma ogni file è locale al componente che lo importa. I nomi delle classi vengono resi unici in fase di build, quindi la collisione globale sparisce e con essa la paura di cancellare.

/* Card.module.css */
.card {
  border-radius: 8px;
  padding: 1.5rem;
  background: var(--superficie);
}
import stili from "./Card.module.css";

export function Card({ children }) {
  return <div className={stili.card}>{children}</div>;
}

È l'opzione più sottovalutata delle tre. Tieni il CSS vero, con tutta la sua espressività, e ottieni l'isolamento che era il problema principale. Funziona senza configurazione in Next.js e in Vite. Quello che non ti dà sono i token di design: la scala di valori te la costruisci tu.

Le variabili CSS native

Hanno risolto parte del problema storico e molti non se ne sono accorti, perché sono arrivate quando l'abitudine ai preprocessori era già consolidata.

:root {
  --spazio-1: 0.5rem;
  --spazio-2: 1rem;
  --colore-primario: #2563eb;
  --raggio: 8px;
}

[data-tema="scuro"] {
  --colore-primario: #60a5fa;
}

Sono variabili vere, che vivono nel browser, non sostituzioni fatte in compilazione come quelle di Sass. Cambiano a runtime, si possono ridefinire per ambito, e rendono un tema scuro una questione di poche righe invece di un foglio di stile parallelo.

Con queste, un design system in CSS classico — la scala di spaziature, i colori, i raggi — è perfettamente fattibile senza strumenti aggiuntivi.

L'annidamento nativo e il resto

Il CSS moderno ha preso in casa l'annidamento, :has(), i layer di cascata (@layer) che permettono di governare l'ordine di priorità in modo esplicito, e il container query che risponde alla larghezza del contenitore invece che della finestra. Molti dei motivi per cui servivano strumenti esterni sono venuti meno.

Il punto non è che Tailwind sia diventato inutile. È che il "CSS classico" del 2026 non è quello che molti hanno in mente, e il confronto va fatto con quello vero.

La tabella

CSS classicoTailwindCSS Modules
Serve una buildNo
IsolamentoNessuno, tutto globaleTotaleTotale, per file
Nomi da inventareSempreMaiPochi e locali
Cancellare senza pauraNo
Leggibilità del markupOttimaPeggioreOttima
Coerenza dei valoriDa disciplinaImposta dalla scalaDa disciplina
Curva inizialeBassaMediaBassa
Peso del CSS finaleCresce nel tempoStabileProporzionale ai componenti
Espressività del CSSCompletaLimitata alle utilitàCompleta
Portabilità del markupAltaBassaAlta
Adatto a team grandiServe convenzione rigida

Cosa fa perdere ore

  • Usare @apply per ricreare classi semantiche in Tailwind. Ottieni gli svantaggi di entrambi: un nome da inventare, un file che cresce e una classe globale che nessuno saprà se può cancellare.
  • Mescolare i due approcci senza una regola. Metà componenti con classi di utilità e metà con un foglio di stile: quando qualcosa non si applica, devi cercare in due posti e la specificità decide in modi che non prevedi.
  • Costruire nomi di classe concatenando stringhe. bg-${colore}-500 non funziona, perché lo strumento cerca classi complete nei sorgenti.
  • Passare a Tailwind un progetto che funziona già. Riscrivere un design system esistente costa moltissimo per un beneficio incerto. Se proprio, si fa sui componenti nuovi.
  • Scrivere CSS classico senza @layer né convenzioni, e poi stupirsi che dopo un anno serva !important.
  • Scegliere in base a cosa fa il progetto più popolare del momento invece che in base a quante persone toccheranno il tuo codice e per quanto tempo.

Il verdetto per caso d'uso

Sito piccolo, landing page, portfolio, blog statico → CSS classico. Cento righe scritte a mano sono più semplici da leggere, non richiedono nessuna build e i problemi di scala non esistono. Aggiungere Tailwind qui significa introdurre una dipendenza per risolvere un problema che non hai.

Nessun processo di build → CSS classico, senza discussione. Tailwind ha bisogno di analizzare i sorgenti e generare il file: senza pipeline non è un'opzione.

Applicazione con molte schermate, in crescita, con più persone che la toccano → Tailwind. È lo scenario per cui è stato pensato: il costo dell'HTML verboso resta basso, il beneficio della coerenza e del "cancello senza paura" cresce con il tempo e con il numero di persone.

Design system già esistente che funziona → tienilo. Hai già risolto il problema che Tailwind risolve. Sostituirlo è lavoro puro senza ritorno.

Team che padroneggia il CSS e ha convenzioni condivise → CSS classico o CSS Modules. Se le convenzioni reggono davvero, il problema principale è già gestito e il CSS vero è più espressivo.

Progetto a componenti dove vuoi CSS vero → CSS Modules. Il compromesso migliore quando l'HTML verboso ti dà fastidio ma l'isolamento ti serve. È la scelta che consiglio più spesso e quella di cui si parla meno.

Se non conosci il CSS → impara il CSS. Vale per entrambe le strade: Tailwind è uno strato sopra flexbox, grid e il box model, e senza quelle basi aggiungi classi a caso finché l'aspetto non torna.

In sintesi

La scelta non è tra due sintassi: è tra avere un punto di controllo centralizzato e avere la certezza di cosa stai toccando.

I problemi del CSS classico sono reali ma compaiono su una certa scala: i nomi, la specificità, e soprattutto il fatto che nessuno cancella mai niente perché nessuno sa chi usa cosa.

Tailwind risolve quelli e ne introduce altri: markup verboso, revisioni del codice più faticose, e una dipendenza da uno strumento di build che su un progetto piccolo non ripaga.

CSS Modules e le variabili CSS native sono l'opzione di mezzo che quasi nessuno considera, e su un progetto a componenti spesso sono la risposta migliore di entrambe.

La regola pratica: più schermate, più persone e più anni di vita spingono verso Tailwind; meno di tutto questo, o un design system che già funziona, spingono verso il CSS scritto a mano.

Per il funzionamento delle classi di utilità, vedi cos'è Tailwind CSS. Per il contesto a componenti in cui questa scelta si pone, vedi cos'è React e cos'è il responsive design.