Un pulsante di attivazione/disattivazione della modalità Buio consente agli utenti di eseguire l'override della combinazione di colori del sistema per un sito.
L'override viene applicato aggiornando <meta name="color-scheme">: light dark significa "segui la preferenza di sistema", light o dark blocca uno schema esplicito.
I colori (light-dark()), i colori di sistema e l'interfaccia utente nativa si basano tutti sulla proprietà CSS color-scheme, quindi l'opzione di attivazione/disattivazione funziona mantenendo questa proprietà sincronizzata con <meta> (vedi Rifletti l'override nel CSS).
Attivazione/disattivazione persistente, controllo delle impostazioni o nessuna attivazione/disattivazione?
La maggior parte dei siti non ha bisogno di un pulsante di attivazione/disattivazione della combinazione di colori persistente nell'UI del sito (intestazione, navigazione, piè di pagina e così via). Segui le preferenze di sistema per impostazione predefinita e, se è necessario un override manuale, inserisci il controllo in una superficie di impostazioni separata: una pagina, un riquadro o un overlay delle impostazioni.
La scelta di uno schema rispetto al sistema operativo è un'intenzione legittima, ma rara, e le intenzioni rare appartengono alla divulgazione progressiva, non a un controllo visibile in ogni momento.
I pulsanti di attivazione/disattivazione persistenti si trovano principalmente sui siti rivolti agli sviluppatori o correlati allo sviluppo (ad esempio per i designer), dove il passaggio da uno schema all'altro è un'attività molto più frequente rispetto all'utente web medio. NON aggiungerne uno solo perché è un pattern comune sui siti per sviluppatori: l'interesse dello sviluppatore per questo controllo non è rappresentativo degli utenti tipici.
Implementazione
Innanzitutto, segui tutti i passaggi descritti in Modalità Buio per supportare entrambi gli schemi, utilizzando come impostazione predefinita la preferenza di sistema.
Modello dei dati
Il modello di dati per l'attivazione/disattivazione della modalità Buio in genere include tre stati:
- Sistema (nessun valore memorizzato): la UI segue la combinazione di colori del sistema. Idealmente, questa dovrebbe essere l'impostazione predefinita.
- Chiaro (memorizzato come
"light"): la UI utilizza il tema chiaro indipendentemente dalla combinazione di colori del sistema. - Scuro (memorizzato come
"dark"): la UI utilizza il tema scuro indipendentemente dalla combinazione di colori del sistema.
Questo stato viene solitamente memorizzato in localStorage e riflesso in un elemento <meta name="color-scheme"> nell'intestazione del documento.
Rifletti l'override nel CSS
<meta> è solo un suggerimento di presentazione: qualsiasi dichiarazione color-scheme nel CSS dell'autore lo sostituisce.
Poiché la modalità Buio imposta color-scheme: light dark su :root, l'aggiornamento della sola <meta> è un'operazione senza effetto: il CSS ha la precedenza.
Mappa nuovamente <meta> alla proprietà in modo che la cascata la segua:
:root {
color-scheme: light dark;
&:has(> head > meta[name="color-scheme"][content="dark"]) {
color-scheme: dark;
}
&:has(> head > meta[name="color-scheme"][content="light"]) {
color-scheme: light;
}
}
NON impostare come hardcoded color-scheme: light o color-scheme: dark come radice predefinita; la dichiarazione di base DEVE rimanere light dark.
Il CSS NON DEVE dipendere da JS: se JS non viene mai eseguito, <meta> rimane light dark e il sito segue la preferenza di sistema, senza problemi.
Persistenza e prevenzione del FOUC
Mantieni l'override in localStorage; rimuovi la voce quando torni alle impostazioni predefinite del sistema.
Per evitare un flash dello schema errato, applica il valore memorizzato in uno script incorporato (NON type=module, NON defer) posizionato immediatamente dopo l'elemento <meta>:
<meta name="color-scheme" content="light dark">
<script>
document.querySelector('meta[name="color-scheme"]').content = localStorage.getItem("color-scheme") ?? "light dark";
</script>
- Questo script in linea esiste solo per la prevenzione del FOUC. Mantienilo il più piccolo possibile; il codice JS aggiuntivo per la gestione dell'attivazione/disattivazione della combinazione di colori può essere caricato in un secondo momento.
- In rari casi, l'accesso a
localStoragepuò generare un errore (ad es. dati del sito bloccati), ma poiché questo script non fa altro, l'unico effetto collaterale sarebbe un errore della console. Se questo è importante, inserisci il codice intry .. catch. Assicurati che il tema sia ancora applicato alla pagina, anche se non può essere reso permanente. - L'override può cambiare da un'altra scheda: gestisci l'evento
storagediwindowper mantenere la sincronizzazione. - NON utilizzare
matchMedia()per rimuovere il valore memorizzato quando la preferenza di sistema cambia in modo da corrispondere. Il sistema operativo di molti utenti cambia automaticamente gli schemi in base all'ora del giorno; la rimozione del valore memorizzato ogni volta che i due schemi coincidono renderebbe impossibile bloccare uno schema.
Branching per HTML e valori non di colore
I colori non richiedono ulteriori interventi: una volta mappato <meta> a color-scheme (sopra), light-dark() segue l'override.
Questa sezione riguarda l'adattamento di altri valori (ad es. font-weight, origini multimediali e così via).
Quando la pagina segue semplicemente la preferenza di sistema, (prefers-color-scheme: dark) può essere utilizzato per la ramificazione, anche nelle origini <picture> o <video>.
L'override della combinazione di colori aggiunge un'ulteriore complicazione: la preferenza di sistema non è più la fonte di attendibilità e per le API che accettano solo query supporti non esiste un'alternativa diretta.
NON fare affidamento esclusivamente su classi applicate tramite JS come .dark per la ramificazione, poiché non saranno corrette se JS non viene caricato e l'impostazione predefinita del sistema operativo è scura.
Puoi combinare la query supporti con un selettore :root:has(> head > meta[name="color-scheme"][content="dark"]) (o light) per creare una diramazione.
Per informazioni dettagliate su come implementare questa soluzione in modo elegante, consulta Combinazioni di selettori e regole @.
Anche le opzioni del controllo sono rami non di colore: includi entrambi gli stati nel markup (icona più testo dell'azione nascosto visivamente, ad esempio "Passa al tema scuro") e nascondi quello non attivo tramite questi selettori.
display: none rimuove anche l'opzione ridondante dalla tecnologia per la disabilità, in modo che il controllo non richieda JS per rimanere aggiornato quando la preferenza di sistema cambia.
Per i contenuti multimediali in HTML, l'unico modo al momento è includere entrambe le versioni come elementi separati e attivare/disattivare la visibilità in modo appropriato.
Nascondere gli elementi <source> con display: none non funziona.
Interfaccia utente
Due o tre stati?
In tutti i casi, la UI DEVE supportare il ripristino o l'impostazione della combinazione di colori sul sistema.
Preferisci la visualizzazione di due stati nei pulsanti di attivazione/disattivazione con spazio limitato, ad esempio i pulsanti di attivazione/disattivazione persistenti nel chrome del sito (intestazione, navigazione, piè di pagina e così via) in cui lo spazio è limitato e la modifica delle impostazioni è solitamente ortogonale all'obiettivo dell'utente.
Un controllo della combinazione di colori in una superficie di impostazioni separata (pagina, riquadro o overlay) è uno scenario diverso e PUÒ esporre esplicitamente tutti e tre gli stati ("Chiaro", "Scuro", "Sistema"): in questo caso, l'utente sta già prendendo decisioni deliberate sul comportamento futuro e c'è spazio per spiegare le opzioni.
I tre stati espliciti sono giustificati anche se il sito implementa schemi sensibili al contesto (ad esempio, una modalità Luce più scura quando il sistema operativo è in modalità Buio), poiché "Luce" e "Sistema (attualmente Luce)" sono effettivamente diversi.
Pulsanti di attivazione/disattivazione a due stati
Quando viene utilizzato un controllo di questo tipo, tende a essere una regolazione temporanea per il comfort ("la luce è troppo intensa in questo momento"), anziché garantire che lo stato attuale venga mantenuto a lungo termine. Pertanto, per i pulsanti di attivazione/disattivazione a due stati, è sufficiente visualizzare due delle tre impostazioni: sistema (in modo che l'impostazione possa essere ripristinata) e l'opposto attuale del sistema, memorizzato come valore letterale attuale.
Gli unici due stati dovrebbero essere:
- Predefinito di sistema: nessun valore memorizzato, contenuti
<meta>light dark. Visualizzato come il valore risolto corrente (ad es. un'icona a forma di sole quando è chiaro). - Override: archiviato letteralmente come
lightodark.
In sostanza, si tratta di un controllo a tre stati (light dark, light, dark) in cui lo stato esplicito corrispondente alla preferenza di sistema corrente non è raggiungibile.
Quando l'utente attiva/disattiva:
- Schema di destinazione = l'opposto dello schema attualmente visualizzato (valore memorizzato, se presente, altrimenti preferenza di sistema). L'intento dell'utente è "seleziona l'opposto di ciò che vedo in questo momento", NON "seleziona l'inverso del predefinito di sistema".
- Se il target è diverso dalla preferenza di sistema corrente, memorizzalo letteralmente.
- Se la destinazione corrisponde alla preferenza di sistema corrente, l'utente sta annullando la modifica: rimuovi il valore memorizzato. NON memorizzarlo, altrimenti lo schema verrebbe bloccato in modo invisibile rispetto a future modifiche del sistema.
- Imposta i contenuti di
<meta>sul valore memorizzato o sulight darkse non è presente alcun valore.
IMPORTANTE: la divergenza deve essere controllata solo al momento della memorizzazione, mai retroattivamente: un valore memorizzato che la preferenza di sistema modifica in un secondo momento per corrispondere DEVE essere conservato. Il sistema operativo di molti utenti cambia automaticamente gli schemi in base all'ora del giorno; la rimozione del valore memorizzato ogni volta che i due schemi coincidono renderebbe impossibile bloccare uno schema.
Scenario di esempio, a partire dal sistema operativo impostato su chiaro:
- L'utente attiva/disattiva l'opzione. La modalità Buio è diversa dalla preferenza di sistema, quindi viene memorizzato
dark; il sito diventa scuro. - L'impostazione del sistema operativo passa alla modalità Buio. Il sito rimane scuro (il valore memorizzato ora corrisponde alla preferenza di sistema, ma viene mantenuto).
- L'impostazione del sistema operativo torna a essere chiara. Il sito rimane scuro.
- L'utente attiva/disattiva l'opzione. La destinazione (chiaro) corrisponde alla preferenza di sistema, quindi il valore memorizzato viene rimosso e il sito segue nuovamente il sistema.
Pulsanti di attivazione/disattivazione a tre stati
Quando c'è più spazio e gli utenti sono già propensi a impostare preferenze a lungo termine, un controllo a tre stati può fornire maggiore chiarezza. In questo caso, il modello di dati viene mappato in modo chiaro alle tre opzioni della UI: sistema, chiaro e scuro.
Per ridurre il carico cognitivo, l'opzione "Sistema" deve mostrare anche l'impostazione di sistema corrente, ad esempio tramite:
- Icona, ad esempio l'icona di un sole in basso a destra dell'icona di sistema
- Testo, ad esempio "Sistema (attualmente chiaro)"