Nicola Bonaita
18 min

Nell''ultimo periodo, complice l'implementazione su piattaforma iOS, si è visto un incremento notevole di siti web e applicazioni che permettono di scegliere tra la modalità chiara e modalità scura.
In questo articolo vedremo perché ha senso, analizzeremo diverse opzioni ed approcci nell'implementare la modalità scura e delle considerazioni tecniche. Presenterò inoltre alcuni suggerimenti di design.
Ciao, sono Nicola Bonaita, da oltre 5 anni mi occupo di Siti Internet e di Digital Marketing. Da un paio di anni ho avviato questo progetto dal nome ÜberDigital, con l'obiettivo di raccontare il mio percorso in questo settore. Se vuoi scoprirne di più su di me, ti invito a cliccare sulla pagina Chi Sono o a scrivermi una mail.
Dare la possibilità agli utenti del proprio sito web di scegliere tra Modalità scura e Modalità chiara è sicuramente un grosso vantaggio in termini esperienza utente.
Ma prima, cerchiamo di essere sulla stessa lunghezza d'onda con i termini.
Di cosa si tratta? Sostanzialmente una modifica cromatica del tema grafico di piattaforme o siti internet, ovvero:

Molto probabilmente, il tema predefinito che gli utenti ottengono alla prima visita, almeno nella maggior parte dei casi è il tema chiaro (sebbene si possa fare in modo che sia il browser dell'utente a fare questa scelta per noi, come vedremo più avanti in questo articolo).
Il modo più semplice per alternare le due modalità (cosa che può essere eseguita automaticamente, come vedremo) è permettere all'utente di passare dalla visualizzazione chiara a quella scura, per esempio attraverso il click di un pulsante.
Ci sono diversi approcci per fare questo:
Il trucco, in questo caso, al click del pulsante, viene scambiata la classe .light-theme con .dark-theme per cambiare uno stile in qualsiasi punto della pagina.
<body class="dark-theme || light-theme">
Ecco uno script per un pulsante che alternerà quella classe, ad esempio:
// Seleziona il pulsante (in questo caso con classe .btn-toggle)
const btn = document.querySelector('.btn-toggle');
// Rileva il click del pulsante
btn.addEventListener('click', function() {
// Quindi scambia (aggiungi/rimuovi) la classe .dark-theme al tag body
document.body.classList.toggle('dark-theme');
})
Ecco come possiamo usare questa idea:
<body>
<button class="btn-toggle">Toggle Dark Mode</button>
<h1>Ciao! Questo è un titolo</h1>
<p>Io sono un testo noioso, esisto solo per lo scopo di questa demo.</p>
<p>E io sono come il mio fratello qui sopra, perché due è sempre meglio di uno.</p>
<a href="#">Io sono un link, non cliccarmi!</a>
</body>
L'idea generale di questo approccio è di creare la grafica degli elementi come faremmo normalmente, chiamare quindi queste regole grafiche la nostra modalità "predefinita", quindi creare un set completo di stili di colore che possiamo usare come modalità scura, inverso dal precedente, usando una classe impostata sull'elemento.
Fatemi spiegare meglio: diciamo che il nostro valore predefinito è una combinazione di colori chiari. Tutti questi stili chiari sono scritti esattamente nello stesso modo in cui normalmente imposti le regole grafiche del tuo sito usando il codice CSS. Dato il nostro codice HTML (visto poco sopra), applichiamo uno stile globale al corpo e ai collegamenti.
body {
color: #222;
background: #fefefe;
}
a {
color: #0033cc;
}
Bene, abbiamo testo scuro (#222) e link scuri (#0033cc) su sfondo chiaro (#fefefe). Il nostro tema "predefinito", quello con la visualizzazione del colore chiaro, è impostato bene. Ora definiamo, per le stesse proprietà, dei valori opposti, questa volta impostati su una classe differente, valida per la modalità scura.
body {
color: #222;
background: #fefefe;
}
a {
color: #0033cc;
}
/* Stili grafici per modalità scura */
body.dark-theme {
color: #eee;
background: #121212;
}
body.dark-theme a {
color: #809fff;
}
Gli stili del tema scuro discenderanno dalla stessa classe genitore, che in questo esempio è .dark-theme, che abbiamo applicato al tag <body> .
Come possiamo "cambiare" le classi del <body> per impostare le classi con gli stili grafici per la modalità scura? Possiamo usare JavaScript! Come abbiamo visto all'inizio dell'articolo, selezioneremo la classe del pulsante (.btn-toggle), aggiungeremo un listener per quando viene cliccato, quindi aggiungeremo la classe del tema scuro (.dark-theme) all'elenco delle classi dell'elemento <body>.
Possiamo anche sfruttare la potenza delle variabili CSS per creare un tema scuro! Ci aiuta a evitare di dover scrivere set di regole di stile separati per ogni tema, rendendo molto più veloce la scrittura degli stili e molto più facile apportare modifiche a un tema se necessario.
Potremo ancora scegliere di scambiare una classe del corpo e utilizzare quella classe per reimpostare le proprietà personalizzate:
// Seleziona il pulsante (in questo caso con classe .btn-toggle)
const btn = document.querySelector('.btn-toggle');
// Rileva il click del pulsante
btn.addEventListener('click', function() {
// Quindi scambia (aggiunge/rimuovi) la classe .dark-theme al tag body
document.body.classList.toggle('dark-theme');
})
Innanzitutto, definiamo i valori di colore chiaro predefiniti come proprietà personalizzate sull'elemento <body>:
body {
--text-color: #222; /*colore del testo*/
--bkg-color: #fff; /*colore dello sfondo*/
--anchor-color: #0033cc; /*colore del testo dei link*/
}
Ora possiamo ridefinire quei valori su una classe del <body> .dark-theme proprio come abbiamo fatto nel primo metodo:
body.dark-theme {
--text-color: #eee; /*colore del testo*/
--bkg-color: #121212; /*colore dello sfondo*/
--anchor-color: #809fff; /*colore del testo dei link*/
}
Ecco i nostri set di regole per gli elementi body e link che utilizzano variabili personalizzate:
body {
color: var(--text-color);
background: var(--bkg-color);
}
a {
color: var(--anchor-color);
}
In questo modo le proprietà (Colore del testo, colore di sfondo, colore del testo dei link) prende il valore della variabile impostata (es: --text-color). Se è stata attività la modalità scura, il valore sarà #eee; mentre se fosse attiva la modalità chiara, il valore sarà #222.
Avremmo potuto anche definire le nostre proprietà personalizzate all'interno del documento :root. È una pratica totalmente legittima e molto comune. In tal caso, tutte le definizioni degli stili del tema predefinito andrebbero all'interno di
:root { }e tutte le proprietà del tema scuro andrebbero all'interno di:root.dark-mode { }.
Invece di tenere tutti gli stili grafici insieme, all'interno di un unico foglio di stile, potremmo invece passare da un foglio di stile all'altro per ogni tema scelto, chiaro o scuro.
Ciò presuppone che tu abbia almeno due fogli di stile completi pronti per l'uso.
Ad esempio, un tema chiaro predefinito come light-theme.css:
/* light-theme.css */
body {
color: #222;
background: #fff;
}
a {
color: #0033cc;
}
Quindi creiamo gli stili per il tema scuro e li salviamo in un foglio di stile separato che chiameremo dark-theme.css.
/* dark-theme.css */
body {
color: #eee;
background: #121212;
}
body a {
color: #809fff;
}
Il risultato sarà avere due fogli di stile separati, uno per ciascuna modalità, che possiamo collegare nella sezione HTML . Quello inserito nel codice HTML sarà quello predefinito, nell'esempio il tema chiaro.
<!DOCTYPE html>
<html lang="it">
<head>
<!-- Light theme stylesheet -->
<link href="light-theme.css" rel="stylesheet" id="theme-link">
</head>
<!-- etc. -->
</html>
Al tag <link> abbiamo inserito un ID #theme-link in modo da poterlo selezionare con JavaScript per, ancora una volta, passare dalla modalità chiara a quella scura. Solo che questa volta, stiamo alternando due file differneti invece delle due classi.
// Seleziona il pulsante (in questo caso con classe .btn-toggle)
const btn = document.querySelector(".btn-toggle");
// Seleziona il foglio di stile <link>
const theme = document.querySelector("#theme-link");
// Rileva il click del pulsante
btn.addEventListener("click", function() {
// Se l'URL contiene "ligh-theme.css"
if (theme.getAttribute("href") == "light-theme.css") {
// ... scambialo con "dark-theme.css"
theme.href = "dark-theme.css";
// Oppure...
} else {
// ... cambia con "light-theme.css"
theme.href = "light-theme.css";
}
});
Il metodo "giusto" dipende dai requisiti del tuo progetto. Se stai realizzando un progetto di grandi dimensioni, ad esempio, potresti utilizzare le proprietà CSS per aiutarti, visto che sicuramente ti troverai a gestire una quantità di codice di grandi dimensioni. D'altra parte, se il tuo progetto deve supportare i browser legacy, allora sarà necessario applicare un altro approccio.
Preciso una cosa: non esiste un metodo migliore di un'altro, così come non esiste un solo metodo. A volte il percorso più efficace sarà una combinazione di metodi differenti.
Seconda precisazione: potrebbero esserci anche altri metodi possibili oltre a quelli che ti ho presentato, anche migliori, qualora avessi piacere puoi inviarmi una email per parlarne.
Per il momento abbiamo utilizzato un pulsante per passare dalla modalità chiara a quella scura, ma possiamo semplicemente lasciare che sia il sistema operativo dell'utente a fare la scelta per noi. Ad esempio, molti sistemi operativi consentono agli utenti di scegliere tra temi chiari e scuri direttamente nelle impostazioni di sistema.
La funzione di media query prefers-color-scheme gode del supporto dei principali browser, tra cui Chrome 76+, Firefox 67+, Chrome Android 76+, Safari 12.5+ (13+ su iOS) e Samsung Internet Browser. Non supporta Internet Explorer. Tuttavia, secondo i dati più aggiornati, possiamo stimare che oltre l'80% degli utenti siano inclusi con i browser che le supportano. Direi sufficiente.
I sistemi operativi che attualmente supportano la modalità scura includono MacOS (Mojave o versioni successive), iOS (13.0+), Windows (10+) e Android (10+).

Come abbiamo appena visto, il CSS ha una media query che può essere utilizzata per rilevare le preferenze della combinazione di colori impostate del sistema dell'utente. È possibile avere tre possibili valori: nessuna preferenza, chiaro e scuro. Se vuoi approfondire, leggi di più su MDN.
@media (prefers-color-scheme: dark) {
/* Gli stili della modalità scura vanno qui */
}
@media (prefers-color-scheme: light) {
/* Gli stili della modalità chiara vanno qui */
}
Per usarlo, possiamo inserire gli stili del tema scuro all'interno della media query.
@media (prefers-color-scheme: dark) {
body {
color: #eee;
background: #121212;
}
a {
color: #809fff;
}
}
Ora, se un utente ha abilitato la modalità scura nelle impostazioni di sistema, otterrà gli stili della modalità scura del tuo sito per impostazione predefinita. Non dobbiamo ricorrere a JavaScript o script lato server per decidere quale modalità utilizzare. Eh si, non abbiamo nemmeno più bisogno di un pulsante!
Un'altro metodo è rivolgerci a JavaScript per rilevare la combinazione di colori preferita dall'utente. Questo è molto simile al primo metodo con cui abbiamo lavorato, solo che stiamo usando matchedMedia() per rilevare le preferenze dell'utente.
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');nnif (prefersDarkScheme.matches) {n document.body.classList.add('dark-theme');n} else {n document.body.classList.remove('dark-theme');n}
Ti segnalo però uno svantaggio nell'usare JavaScript: è possibile che ci sia un rapido lampo del tema chiaro perché JavaScript viene eseguito dopo il CSS. Questo potrebbe essere frainteso come un bug.
E, naturalmente, possiamo invece scambiare i fogli di stile come abbiamo fatto nel secondo metodo. Questa volta colleghiamo entrambi i fogli di stile e utilizziamo la media query per determinare quale viene applicato.
Abbiamo appena esaminato come tenere conto delle preferenze di combinazione di colori impostate a livello di sistema dell'utente.
Ma cosa succede se gli utenti desiderano ignorare la preferenza di sistema per un sito? Solo perché un utente preferisce la modalità scura per il proprio sistema operativo non significa che la preferisca su un sito web sempre. Ecco perché fornire un modo per ignorare manualmente la modalità scura, nonostante le impostazioni di sistema, è una buona idea.
Usiamo l'approccio delle proprietà personalizzate CSS per dimostrare come farlo. L'idea è di definire le proprietà personalizzate per entrambi i temi come abbiamo fatto prima, racchiudere gli stili scuri nella media query prefers-color-scheme, quindi definendo una classe .light-theme all'interno della quale possiamo sovrascrivere le proprietà della modalità oscura , se l'utente desidera passare da una modalità all'altra.
/* Colori di default */
body {
--text-color: #222;
--bkg-color: #fff;
}
/* Colori per la versione scura */
body.dark-theme {
--text-color: #eee;
--bkg-color: #121212;
}
/* Stili per gli utenti che preferiscono la modalità scura a livello di sistema operativo */
@media (prefers-color-scheme: dark) {
/* Default per la modalità scura */
body {
--text-color: #eee;
--bkg-color: #121212;
}
/* Sovrascrivi la modalità scura con la modalità chiara se l'utente decide di cambiare */
body.light-theme {
--text-color: #222;
--bkg-color: #fff;
}
}
Ora possiamo tornare al nostro fidato pulsante per alternare tra modalità chiara e scura. In questo modo, per impostazione predefinita, rispetteremo la preferenza del colore impostato del sistema operativo, consentendo ugualmente all'utente di cambiare manualmente i temi.
// Rileva il click del pulsante
btn.addEventListener("click", function() {
// Se il sistema operativo ha modalità scura...
if (prefersDarkScheme.matches) {
// ...allora applica la classe .light-theme per sovrascrivere
document.body.classList.toggle("light-theme");
// Altrimenti...
} else {
// ...applica la classe .dark-theme class per sovrascrivere la modalità chiara
document.body.classList.toggle("dark-theme");
}
});
Tutte le modalità descritte finora fanno esattamente quello per cui ti trovi qui: permettono di impostare una modalità chiara e/o scura del nostri sito web in base a una preferenza del sistema operativo o al click di un pulsante. Tutto questo è fantastico, ma devo interrompere i festeggiamenti: la scelta impostata viene cancellata quando l'utente visita un'altra pagina del sito o ricarica la pagina corrente.
Per ovviare a questo problema abbiamo bisogno di salvare la scelta dell'utente in modo che venga applicata in modo coerente in tutto il sito, anche nelle sue visite successive. Per fare ciò, abbiamo due strade da percorrere: possiamo salvare la scelta dell'utente nel localStorage del browser oppure utilizzare un cookie.
Diamo un'occhiata ad entrambi gli approcci.
Abbiamo uno script che salva il tema selezionato in localStorage quando l'utente scegli la modalità preferita. In altre parole, quando la pagina viene ricaricata, lo script recupera la scelta da localStorage e la applica, lo stesso viene applicato quindi anche su una seconda visita a distanza di tempo.
Come già anticipato più in alto in questo articolo, il codice JavaScript viene spesso eseguito dopo quello CSS, quindi questo approccio è soggetto al "lampo di tema errato".
// Seleziona il pulsante
const btn = document.querySelector(".btn-toggle");
// Seleziona la preferenza del tema da localStorage
const currentTheme = localStorage.getItem("theme");
// Se il tema corrente è "dark"...
if (currentTheme == "dark") {
// ... allora usa la classe .dark-theme
document.body.classList.add("dark-theme");
}
// Rileva il click sul pulsante
btn.addEventListener("click", function() {
// Scambia la classe .dark-theme ad ogni click
document.body.classList.toggle("dark-theme");
// Immaginiamo che il tema sia chiaro
let theme = "light";
// Se il body contiene la classe .dark-theme ...
if (document.body.classList.contains("dark-theme")) {
// ...allora applica il tema scuro
theme = "dark";
}
// Infine salva la scelta in localStorage
localStorage.setItem("theme", theme);
});
Per evitare il lampo del tema errato, possiamo utilizzare uno script lato server usando il PHP. Invece di salvare la preferenza del tema dell'utente in localStorage, creeremo un cookie da JavaScript e lo salveremo lì.
// Seleziona il pulsante
const btn = document.querySelector(".btn-toggle");
// Rileva il click del pulsante
btn.addEventListener("click", function() {
// Imposta la classe .dark-theme al body
document.body.classList.toggle("dark-theme");
// Immaginiamo che il tema sia chiaro
let theme = "light";
// Se il body contiene la classe .dark-theme ...
if (document.body.classList.contains("dark-theme")) {
// ...allora applica il tema scuro
theme = "dark";
}
// Infine salva la scelta in un Cookie
document.cookie = "theme=" + theme;
});
Ora possiamo verificare l'esistenza di quel cookie e caricare il tema appropriato applicando la classe appropriata al tag <body>.
<?php
$themeClass = '';
if (!empty($_COOKIE['theme']) && $_COOKIE['theme'] == 'dark') {
$themeClass = 'dark-theme';
}
?>
<!DOCTYPE html>
<html lang="it">
<!-- etc. -->
<body class="<?php echo $themeClass; ?>">
<!-- etc. -->
</body>
</html>
Ecco come farlo usando il metodo dei fogli di stile separati:
<?php
$themeStyleSheet = 'light-theme.css';
if (!empty($_COOKIE['theme']) && $_COOKIE['theme'] == 'dark') {
$themeStyleSheet = 'dark-theme.css';
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- etc. -->
<link href="<?php echo $themeStyleSheet; ?>" rel="stylesheet" id="theme-link">
</head>
<!-- etc. -->
Unificando i vari metodi spiegati in questo articolo possiamo ottenere quanto segue:
È il metodo che personalmente ho scelto per il sito sul quale stai leggendo questo articolo.
Vuoi vedere il codice completo? Inviamo pure una email.
Sento spesso dire che implementare la modalità oscura è più facile che progettarne una. Senza aprire un discorso complesso, diamo un'occhiata ad alcune considerazioni per la progettazione di un tema scuro da tenere a mente.
Conosci già le basi: scambiare i valori di colore più chiari con quelli più scuri e viceversa.
Tuttavia, per fare un lavoro come si deve, ci sono alcuni elementi e miglioramenti dell'interfaccia utente che richiedono maggiore attenzione. Diamo un'occhiata a quelli più importanti.
Una buona regola è diminuire un po' la luminosità e il contrasto delle immagini in modo che risultino più confortevoli per gli occhi quando si trovano su uno sfondo scuro. Un'immagine super luminosa su uno sfondo super scuro può risultare fastidiosa da guardare e, oscurando l'immagine si riduce parte di quel forte contrasto.
La funzione CSS filter() è più che in grado di gestire quest'aspetto:
/* Applica il filtro direttamente nel tag body */
body.dark-theme img {
filter: brightness(.8) contrast(1.2);
}
/* Oppure applicalo tramite la media query */
@media (prefers-color-scheme: dark) {
img {
filter: brightness(.8) contrast(1.2);
}
}
Le ombre in modalità oscura sono complicate da gestire. Se semplicemente invertissimo un'ombra scura usando colori chiari, otteniamo questa cosa funky con un'ombra chiara su uno sfondo scuro… e non è affatto appagante.

È possibile utilizzare un'ombra scura in modalità oscura, ma il colore di sfondo deve essere abbastanza "chiaro" (come un grigio scuro) per fornire un contrasto sufficiente per vedere effettivamente l'ombra contro di esso.
In generale l'ombra viene utilizzata per creare un effetto di tridimensionalità degli elementi del sito, "sollevando" dallo sfondo l'elemento a cui è stata applicata l'ombra. L'effetto che ne risulta è che l'elemento più vicino all'utente apparirà "più chiaro" rispetto allo sfondo. Questo concetto NON cambia anche in un'interfaccia scura.
Usa differenti gradazioni dello stesso colore per trasmettere la profondità, impostando gli elementi che vuoi che risultino più in alto con un colore appena più chiaro dello sfondo.

Il trucco qui è molto simile a quanto fatto per le immagini: dobbiamo bilanciare il contrasto tra testo e sfondo. Utilizzare un carattere troppo pesante e otterremo un testo a tutto volume che ci fa venire voglia di allontanarci dallo schermo. Utilizzare un carattere troppo chiaro e affaticheremo gli occhi mentre ci avviciniamo allo schermo per dare un'occhiata più da vicino.
Nello specifico il testo di questo sito è stato impostato su un bianco pesante (#fefefe) ma con applicata un'opacità dell'87%, così come da regolamento del Material Design, il sistema di regole di progettazione utilizzato da Google.

Il testo bianco puro su uno sfondo nero puro sembrerà stridente. Il trucco qui è usare un bianco sporco per il testo e un nero sporco per lo sfondo. Le linee guida per la Materiale Design, ad esempio, consigliano #121212 per lo sfondo, che è il colore utilizzato per lo sfondo di questo sito.
Ci sono ragioni perfettamente valide da entrambe le parti. Alcuni di questi motivi vanno anche oltre l'ambito della sola esperienza utente e includono tempistiche, budget, risorse e sicuramente altri.
Pur comprendendo il motivo per cui potresti non voler implementare una modalità scura sul tuo sito, di seguito trovi i motivi per cui potresti volerne uno:
P.IVA IT04541080166
CF BNTNCL95L26A794I
Mail: nicola@uberdigital.it