Hai mai aggiunto il tema scuro a un sito e ti sei ritrovato con classi Tailwind duplicate per ogni colore? Oppure, peggio, hai usato JavaScript per cambiare stili a runtime, trasformando il CSS in un caos ingestibile? Non sei solo. Lo vediamo spesso nei progetti che ci arrivano: la dark mode viene implementata in modo artigianale, con codice che moltiplica il debito tecnico.
Noi, di Meteora Web, abbiamo affrontato questo problema decine di volte. Su clienti e-commerce, siti vetrina, piattaforme SaaS. E abbiamo imparato che la soluzione più pulita, mantenibile e performante è la class strategy di Tailwind. In questa guida ti spieghiamo perché funziona e come metterla in pratica, partendo dal problema reale.
Perché la class strategy batte qualsiasi altra soluzione
Quando aggiungi un tema scuro, hai due strade classiche: scrivere CSS custom per ogni colore, oppure usare variabili CSS e cambiarle via JavaScript. Entrambe funzionano, ma entrambe hanno un costo di manutenzione che cresce con il progetto.
Con Tailwind e la direttiva dark: ottieni il meglio: le classi di utility restano nel markup, non devi scrivere CSS aggiuntivo, e il toggle del tema è gestito da un unico selettore sull'elemento root. Il browser applica automaticamente le varianti scure quando il genitore ha la classe dark.
Il vero vantaggio: manutenzione zero
Supponi di avere un bottone con sfondo blu chiaro e testo bianco in modalità chiara, e sfondo blu scuro con testo grigio in modalità scura. Con la class strategy scrivi:
<button class="bg-blue-500 dark:bg-blue-800 text-white dark:text-gray-300">Cliccami</button>Fine. Non devi cercare @media (prefers-color-scheme: dark) in due fogli di stile diversi. Tutta la logica visiva sta nel componente. Se domani cambi idea sui colori, modifichi una sola riga.
Configurazione: darkMode: 'class'
Per prima cosa apri tailwind.config.js e imposta la modalità dark su “class” (invece del default “media”). Attenzione: se usi il valore “media”, Tailwind segue automaticamente le preferenze del sistema operativo, ma non ti permette di dare all'utente la scelta manuale. Noi consigliamo sempre “class” per avere controllo totale.
// tailwind.config.js
module.exports = {
darkMode: 'class',
theme: {
extend: {},
},
plugins: [],
}Un errore comune: dimenticare di riavviare il dev server dopo aver cambiato questa opzione. Tailwind non rigenera le varianti fintanto che il processo non riparte.
Implementazione pratica del toggle
Ora devi decidere dove applicare la classe dark. Di solito la metti sull'elemento <html> o sul <body>. Noi preferiamo <html> perché è più radicale e funziona con tutti gli elementi all'interno.
Salvare la preferenza in localStorage
L'utente si aspetta che la scelta venga ricordata tra una visita e l'altra. Usiamo JavaScript per leggere e scrivere localStorage. Ecco uno script minimo da inserire nel <head> (prima di qualsiasi altro codice) per evitare il flash del tema sbagliato:
<script>
// Legge dal localStorage o usa la preferenza di sistema
const theme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
if (theme === 'dark') {
document.documentElement.classList.add('dark');
}
</script>Attenzione: questo script deve essere sincrono e inline, altrimenti vedrai un lampeggio del tema chiaro prima che il DOM venga aggiornato. Un cliente e-commerce con immagini da diversi MB ci ha chiesto di risolvere proprio questo problema: un flash bianco che rovinava l'esperienza su mobile con connessione lenta. Con questo script inline l'abbiamo eliminato.
Toggle button con Vue, React o semplice HTML
Il meccanismo è sempre lo stesso: quando l'utente clicca, inverti la classe dark sull'HTML e aggiorni il localStorage. Ecco un esempio vanilla:
<button id="theme-toggle" aria-label="Cambia tema">🌙</button>
<script>
const toggle = document.getElementById('theme-toggle');
toggle.addEventListener('click', () => {
const html = document.documentElement;
const isDark = html.classList.toggle('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
});
</script>Se usi React, la logica è identica: gestisci lo stato con useState e applichi la classe su <html> con un effetto collaterale (useEffect). In Vue 3, un semplice watch sulla variabile reattiva fa il lavoro.
Stili personalizzati per la dark mode
Tailwind include già molte varianti dark: pronte per i colori predefiniti. Ma se hai bisogno di personalizzare tonalità specifiche (es. un rosso acceso che in dark mode deve diventare più tenue), devi dichiararle in tailwind.config.js nella sezione darkMode o semplicemente usare classi come dark:bg-red-900.
Per elementi non colorati (bordi, ombre, gradienti)
Anche per questi funziona il prefisso dark:. Esempio per un bordo che in modalità chiara è grigio chiaro e in scura grigio scuro:
<div class="border border-gray-300 dark:border-gray-700">...</div>Un errore comune: dimenticare gli stati hover, focus e active. Applica anche a quelli:
<a href="#" class="text-gray-700 hover:text-blue-600 dark:text-gray-300 dark:hover:text-blue-400">Link</a>Gestire il tema in base al sistema operativo (opzione media)
Se per qualche motivo non vuoi dare all'utente la scelta manuale (es. un'app informativa senza login), puoi usare darkMode: 'media'. In questo caso Tailwind applica automaticamente le varianti scure quando il sistema operativo è in dark mode. Non c'è bisogno di JavaScript, ma atterri con un'esperienza meno flessibile.
Noi sconsigliamo questa strada per siti che richiedono una personalizzazione esplicita. Un utente che naviga in modalità chiara di giorno e scura di notte si aspetta di poter decidere, non di essere forzato dal sistema.
Casi reali: errori che abbiamo visto (e risolto)
- Classi dark dimenticate sui componenti chiave. Un form di checkout in un e-commerce aveva il pulsante “Acquista” con sfondo bianco anche in dark mode. Risultato: il testo era invisibile. Controlla sempre ogni componente visibile, non solo il layout.
- JavaScript che aggiunge la classe dopo il rendering. Se lanci lo script in fondo al body, il browser carica prima il CSS chiaro e poi lo sovrascrive. Produce un fastidioso flash. Soluzione: script inline in <head> come mostrato sopra.
- Test insufficienti su mobile. Abbiamo visto siti perfetti su desktop ma con testo illeggibile su mobile a causa di media query scritte male. Tailwind gestisce le varianti responsive separatamente, ma assicurati di testare
dark:sm:bg-gray-800e simili.
In sintesi — cosa fare adesso
- Apri il tuo progetto Tailwind e imposta
darkMode: 'class'intailwind.config.js. Riavvia il dev server. - Aggiungi lo script inline nel <head> per leggere il tema salvato o la preferenza di sistema.
- Crea un toggle (pulsante) che inverte la classe
darksull'HTML e salva in localStorage. - Per ogni componente che ha colori, aggiungi le varianti
dark:necessarie. Non lasciare nessun colore senza controparte scura. - Testa su browser diversi, con tema di sistema chiaro e scuro, e con il localStorage svuotato. Simula anche il cambio di tema a metà navigazione.
Questa strategia non è solo pulita: è anche veloce. Niente CSS extra, niente JavaScript pesante. Il browser applica le varianti direttamente con il cascade. E quando il progetto cresce, ringrazierai di avere tutto in un unico layer di utility.
Noi, di Meteora Web, abbiamo integrato questa tecnica in più di dieci progetti, dal piccolo sito vetrina a piattaforme con decine di migliaia di utenti. Funziona. Ora tocca a te.
Sponsored Protocol