Il dark mode è ormai uno standard atteso dagli utenti: riduce l'affaticamento visivo in condizioni di scarsa luminosità, può risparmiare batteria e dà un tocco moderno all'interfaccia di un sito web o di una web app. Implementare un dark mode switcher è semplice e vale sempre la pena farlo: con poche righe di CSS e JavaScript ottieni una UX pulita e persistente.
Creare un dark mode switcher in JavaScript non è solo un esercizio di stile. L'utente si aspetta un'interfaccia flessibile, che rispetti le sue preferenze e che non lo costringa a forzare le impostazioni di sistema. Avere un pulsante per attivare o disattivare il tema scuro comunica attenzione ai dettagli: non stai solo offrendo contenuti, ma cura nell'esperienza di navigazione.
Su dispositivi con schermi OLED o AMOLED, il tema scuro riduce poi i consumi energetici perché i pixel neri vengono effettivamente spenti. Inoltre, molti studi hanno dimostrato che la modalità scura può ridurre l'affaticamento degli occhi in ambienti poco illuminati, migliorando la permanenza dell'utente sul sito e la leggibilità di notte. Offrire questa possibilità è anche una forma di rispetto per la salute di chi visita il tuo sito.
Di seguito trovi un approccio robusto e accessibile: utilizziamo variabili CSS, rispettiamo la preferenza di sistema (prefers-color-scheme), salviamo la scelta dell'utente in localStorage e sincronizziamo la preferenza tra schede.
Struttura di base per il nostro dark mode switcher
Un toggle semplice e semanticamente corretto può essere realizzato in questo modo con HTML:
<button id="theme-toggle" aria-pressed="false" aria-label="Attiva modalità scura">
🌙
</button>
Definiamo poi le variabili per i colori e i due temi. Usiamo quindi una transizione leggera per rendere il cambio più fluido.
:root {
--bg: #ffffff;
--text: #111111;
--accent: #0077ff;
transition: background-color 250ms ease, color 250ms ease;
}
[data-theme="dark"] {
--bg: #0b0f14;
--text: #e6eef6;
--accent: #66b2ff;
}
html, body {
height: 100%;
background: var(--bg);
color: var(--text);
margin: 0;
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
}
Usando data-theme="dark" sul codice HTML o body rendi il cambio di tema semplice e gestibile da JavaScript.
Rispettare la preferenza di sistema (prefers-color-scheme)
Prima di applicare qualsiasi preferenza dell'utente, è buona pratica leggere le preferenze di sistema:
@media (prefers-color-scheme: dark) {
:root {
--bg: #0b0f14;
--text: #e6eef6;
--accent: #66b2ff;
}
}
Questo assicura che, in assenza di una scelta esplicita, il sito segua il sistema operativo.
JavaScript: attivare il toggle e salvare la preferenza
Ecco il codice che gestisce il click, imposta l'attributo data-theme, aggiorna aria-pressed e salva la scelta in localStorage. Include anche il caricamento iniziale della preferenza, priorizzando localStorage su prefers-color-scheme.
const toggle = document.getElementById("theme-toggle");
const storageKey = "theme-preference";
function applyTheme(theme) {
if (theme === "dark") {
document.documentElement.setAttribute("data-theme", "dark");
toggle.setAttribute("aria-pressed", "true");
toggle.setAttribute("aria-label", "Disattiva modalità scura");
toggle.textContent = "☀️";
} else {
document.documentElement.removeAttribute("data-theme");
toggle.setAttribute("aria-pressed", "false");
toggle.setAttribute("aria-label", "Attiva modalità scura");
toggle.textContent = "🌙";
}
}
function getSystemPreference() {
return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark" : "light";
}
function loadTheme() {
const stored = localStorage.getItem(storageKey);
if (stored) {
applyTheme(stored);
} else {
applyTheme(getSystemPreference());
}
}
toggle.addEventListener("click", () => {
const current = document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light";
const next = current === "dark" ? "light" : "dark";
applyTheme(next);
localStorage.setItem(storageKey, next);
});
// Sincronizza tra schede
window.addEventListener("storage", (e) => {
if (e.key === storageKey) {
applyTheme(e.newValue || getSystemPreference());
}
});
// Applica all'avvio
loadTheme();
Questo script è minimale ma completo: copre toggle, persistenza, sincronizzazione tra schede e fallback alla preferenza di sistema.
Accessibilità e UX
Non bisogna dimenticare l'aspetto accessibilità. Implementare un dark mode in modo responsabile significa garantire contrasti adeguati (rispettando le linee guida WCAG) e fornire sempre alternative per chi non vuole o non può utilizzarlo. Un tema scuro mal progettato rischia di peggiorare la leggibilità, specialmente per utenti con deficit visivi. Per questo motivo, testare il contrasto dei colori scelti è un passaggio fondamentale.
@media (prefers-reduced-motion: reduce) {
:root { transition: none; }
}
Funzionalità avanzate (opzionali)
- Modalità automatica basata sull'orario: imposta il dark mode dopo il tramonto con semplice verifica dell'orario, oppure legalo all'API Geolocation + sunrise/sunset.
- Salvataggio lato server: salva la scelta dell'utente nel profilo per mantenerla tra dispositivi.
- Animazioni e micro-interazioni: usa la Web Animations API per transizioni più ricche, ma controlla prefers-reduced-motion.
- Theme picker con più varianti: invece di solo light/dark, fornisci più schemi (ad es. night, sepia, high-contrast) usando lo stesso approccio data-theme.
Se JavaScript è disabilitato, il sito dovrebbe comunque essere leggibile: assicurati che gli stili di default (light o dark) siano accettabili. Il codice JavaScript migliora l'esperienza ma non dovrebbe essere l'unico modo per visualizzare contenuti.
Un vantaggio ulteriore è che questo approccio non richiede librerie esterne. Framework come Bootstrap o Tailwind CSS offrono già modalità scura, ma implementarla manualmente ti dà un controllo completo sulle variabili e ti permette di integrarla con il tuo design system. In questo modo, se in futuro deciderai di cambiare palette colori, basterà modificare poche variabili CSS invece di ristrutturare centinaia di regole. Questo approccio scalabile riduce i costi di manutenzione e aumenta la coerenza del tuo progetto.
Conclusione
Dal punto di vista del branding, un dark mode switcher ti permette di rafforzare il tone of voice visivo del tuo prodotto. Alcuni brand scelgono un tema scuro elegante per trasmettere modernità e serietà, altri lo usano per enfatizzare elementi grafici luminosi come loghi o pulsanti di call-to-action. In ogni caso, il controllo sull'interfaccia si traduce in un'esperienza utente più coerente e memorabile.
Un dark mode switcher ben costruito può fare la differenza anche dal punto di vista della SEO e delle performance. Riduce infatti la dipendenza da immagini pesanti (usando variabili CSS invece di duplicare asset per temi diversi), migliora i tempi di caricamento e mantiene il DOM più pulito. Motori di ricerca come Google non danno un ranking diretto al dark mode, ma apprezzano i siti veloci, accessibili e user-friendly. Tutti fattori che contribuiscono indirettamente alla visibilità del tuo progetto.
In prospettiva possiamo immaginare che la gestione dei temi diventi sempre più sofisticata. Già oggi alcuni siti offrono theme pickers con più varianti (chiaro, scuro, seppia, high-contrast), e non è escluso che in futuro i browser stessi introducano nuove API per semplificare ulteriormente la gestione del colore. Imparare ora a costruire un dark mode switcher con JavaScript e CSS significa prepararsi a queste evoluzioni e avere basi solide per progetti futuri.
Il dark mode switcher è molto più di un "gadget estetico", è una funzionalità che unisce usabilità, performance, branding e accessibilità. Con pochi passaggi puoi offrire agli utenti un sito moderno, leggero e personalizzabile, capace di adattarsi alle esigenze di ciascuno. E soprattutto, puoi farlo senza appesantire il progetto con librerie esterne, mantenendo il controllo sul codice e la libertà creativa sul design.