Media Query prefers-color-scheme: Implementare Temi Chiari e Scuri con CSS

Principiante
HTML e CSS

Scopri come utilizzare la media query prefers-color-scheme per creare siti web accessibili che si adattano automaticamente alle impostazioni di tema del sistema operativo dell'utente.

Pubblicato
Tag
frontend web design css Accessibilità Dark Mode prefers-color-scheme

Introduzione al Dark Mode e all'Accessibilità

Negli ultimi anni, l'implementazione di un "Dark Mode" (tema scuro) non è più considerata un semplice optional estetico, ma una necessità legata all'esperienza utente (UX) e all'accessibilità. Molti utenti preferiscono i temi scuri per ridurre l'affaticamento visivo in ambienti a bassa luminosità o per risparmiare batteria su dispositivi con schermi OLED, dove i pixel neri sono effettivamente spenti.

Fino a poco tempo fa, per offrire un tema scuro, gli sviluppatori dovevano implementare complessi sistemi basati su JavaScript e cookie o localStorage per salvare la preferenza dell'utente e applicare una classe CSS specifica al body (es. .dark-theme). Oggi, grazie alle moderne specifiche CSS, esiste un modo nativo, performante e automatico per ottenere questo risultato: la media query prefers-color-scheme.

Questa funzionalità permette al browser di interrogare il sistema operativo dell'utente (Windows, macOS, Android, iOS) per sapere se l'utente ha impostato una preferenza globale per i colori chiari o scuri. Se l'utente ha impostato "Scura" nelle impostazioni di sistema, il browser attiverà automaticamente le regole CSS definite all'interno di questa media query.

Come funziona prefers-color-scheme

La media query prefers-color-scheme accetta due valori principali: light (chiaro) e dark (scuro). Quando utilizziamo questa query, stiamo dicendo al browser: "Se l'utente preferisce questo schema di colori, applica questi stili".

Perché usare l'approccio nativo rispetto a JavaScript?

L'utilizzo di CSS nativo offre diversi vantaggi critici:

  1. Zero Flash of Unstyled Content (FOUC): Quando si usa JavaScript per cambiare tema, spesso l'utente vede per una frazione di secondo la pagina bianca prima che lo script carichi la preferenza e applichi il tema scuro. Con CSS, il browser applica lo stile corretto durante il primo rendering.
  2. Performance: Non c'è bisogno di eseguire script lato client per determinare il colore di sfondo.
  3. Rispetto della volontà dell'utente: L'utente non deve configurare ogni singolo sito che visita; il sito si adatta automaticamente a una scelta che l'utente ha già fatto a livello di sistema.

Implementazione Pratica: Strategie di Codifica

Esistono due modi principali per strutturare il CSS per i temi: l'approccio "Override" e l'approccio basato sulle "Variabili CSS" (Custom Properties). Quest'ultimo è di gran lunga il più professionale e manutenibile.

L'approccio con Variabili CSS (Best Practice)

L'idea è definire un set di variabili per i colori in un blocco globale e poi sovrascriverle all'interno della media query. In questo modo, non dovremo riscrivere ogni singola proprietà di ogni elemento, ma cambieremo solo il "valore" dei colori.

Ecco un esempio completo e commentato:

/* 1. Definizione dei colori per il tema CHIARO (Default) */
:root {
  --bg-color: #ffffff;
  --text-color: #333333;
  --accent-color: #007bff;
  --card-bg: #f8f9fa;
  --border-color: #dddddd;
  --transition-speed: 0.3s;
}

/* 2. Sovrascrittura dei colori per il tema SCURO */
@media (prefers-color-scheme: dark) {
  :root {
    --bg-color: #121212;      /* Grigio molto scuro, meglio del nero puro per l'affaticamento */
    --text-color: #e0e0e0;    /* Bianco sporco per evitare contrasti eccessivi */
    --accent-color: #3793ff;  /* Una tonalità di blu più chiara e vibrante per il dark mode */
    --card-bg: #1e1e1e;       /* Sfondo leggermente più chiaro del fondo pagina per dare profondità */
    --border-color: #333333;
  }
}

/* 3. Applicazione delle variabili agli elementi */
body {
  background-color: var(--bg-color);
  color: var(--text-color);
  font-family: sans-serif;
  transition: background-color var(--transition-speed), color var(--transition-speed);
  margin: 0;
  padding: 2rem;
}

.card {
  background-color: var(--card-bg);
  border: 1px solid var(--border-color);
  padding: 1.5rem;
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}

.btn-primary {
  background-color: var(--accent-color);
  color: white;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
}

In questo esempio, abbiamo creato un sistema flessibile. Se decidessimo di cambiare il colore dell'accento per entrambi i temi, dovremmo modificare solo due righe di codice invece di cercare ogni singolo elemento nel documento.

Gestione di Immagini e Media

Un errore comune è dimenticare che le immagini, i loghi o le icone progettate per un fondo bianco possono risultare sgradevoli o invisibili su un fondo scuro. Esistono diverse strategie per gestire questo problema.

Utilizzo dell'elemento <picture>

Il tag HTML <picture> permette di servire immagini diverse in base a diverse condizioni. Possiamo usare l'attributo media per cambiare l'immagine in base al tema:

<picture>
  <!-- Immagine da mostrare se l'utente preferisce il tema scuro -->
  <source srcset="logo-dark.png" media="(prefers-color-scheme: dark)">
  <!-- Immagine di fallback (tema chiaro) -->
  <img src="logo-light.png" alt="Logo Aziendale">
</picture>

Filtri CSS per icone

Se utilizzi icone in formato PNG o JPG che sono nere, puoi invertirne i colori usando i filtri CSS quando il tema scuro è attivo:

@media (prefers-color-scheme: dark) {
  .icon-black {
    filter: invert(1) brightness(2);
  }
}

Esempi Pratici e Casi d'Uso Reali

Caso 1: Il contrasto e l'accessibilità (WCAG)

Non basta invertire il bianco con il nero. Per un sito professionale, è fondamentale rispettare le linee guida WCAG (Web Content Accessibility Guidelines).

Errore: Usare #000000 (nero puro) e #FFFFFF (bianco puro). Questo crea un contrasto troppo netto che può causare "effetto alone" (halation) per persone con astigmatismo. Soluzione: Usare grigi molto scuri (es. #121212) e bianchi opachi (es. #E0E0E0).

Caso 2: Creazione di un "Toggle Manuale" ibrido

Sebbene prefers-color-scheme sia eccellente, alcuni utenti desiderano forzare un tema indipendentemente dal sistema. La strategia migliore è combinare CSS e una piccola parte di JavaScript che aggiunge una classe al body.

/* Default basato su sistema */
:root {
  --bg: #fff; --text: #000;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #121212; --text: #fff;
  }
}

/* Override manuale tramite classe .light-mode o .dark-mode */
body.light-mode {
  --bg: #fff; --text: #000;
}
body.dark-mode {
  --bg: #121212; --text: #fff;
}

Con questo setup, il sito parte con il tema di sistema, ma se l'utente clicca un tasto "Cambia Tema", JavaScript aggiunge la classe .dark-mode o .light-mode, che avendo una specificità maggiore, vince sulla media query.

Errori comuni e FAQ

Perché il mio tema scuro non appare?

  1. Cache del browser: Assicurati di aver svuotato la cache o di essere in modalità incognito.
  2. Impostazioni di Sistema: Verifica che il tuo sistema operativo (es. Windows 10/11 o macOS) abbia effettivamente impostato il tema "Scura". Se è impostato su "Chiaro" o "Automatico (di giorno chiaro)", la media query (prefers-color-scheme: dark) non sarà attiva.
  3. Specificità CSS: Se hai definito colori fissi (es. background: white;) all'interno di classi specifiche, queste vinceranno sulle variabili definite in :root. Usa sempre var(--variable-name).

Posso usare prefers-color-scheme in JavaScript?

Sì, è possibile utilizzare l'oggetto window.matchMedia per rilevare la preferenza via script:

if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  console.log("L'utente preferisce il tema scuro");
}

Prossimi passi

Ora che hai implementato un sistema di temi basato su prefers-color-scheme, puoi approfondire ulteriormente l'estetica e l'usabilità del tuo sito:

  1. Colori di Accento Dinamici: Sperimenta con diverse tonalità di colori primari per il dark mode. I colori saturi che funzionano sul bianco spesso risultano troppo "aggressivi" sul nero; prova versioni desaturate.
  2. Transizioni Fluide: Aggiungi transition: background-color 0.3s ease; al body per evitare che il cambio di tema (se avviene via toggle) sia troppo brusco.
  3. Test di Contrasto: Utilizza strumenti come Chrome DevTools (scheda Lighthouse o Accessibilità) per verificare che il contrasto tra testo e sfondo sia sufficiente per tutti gli utenti.
  4. Supporto per i colori HDR: Esplora le nuove specifiche CSS per i colori ad alta gamma dinamica per rendere i tuoi temi scuri ancora più profondi e vividi su schermi moderni.