Modalità Scuro

La proprietà color-scheme indica le combinazioni di colori (ad esempio chiaro o scuro) supportate dalla tua pagina. In questo modo, il browser viene informato che può applicare automaticamente un tema agli elementi UI nativi, come barre di scorrimento, controlli dei moduli e lo sfondo predefinito del canvas, in modo che corrispondano al design del tuo sito e contribuiscano a ridurre al minimo i flash bianchi durante il caricamento iniziale.

Implementazione

1. Dichiara gli schemi supportati in HTML

OBBLIGATORIO: per evitare un "flash di contenuti senza tema" (FOUC), inserisci un tag <meta> nel tuo <head> per assicurarti che il browser sappia quali temi supporti prima ancora di iniziare il rendering. Sebbene questo tag <meta> aiuti a evitare il FOUC impostando in anticipo il colore iniziale del canvas, potrebbe non eliminare completamente i flash in tutti i browser o in tutte le condizioni di caricamento.

<!-- MANDATORY: Declare support for both light and dark themes -->
<meta name="color-scheme" content="light dark">

2. Applica la combinazione di colori a livello di pagina a :root o html CSS

OBBLIGATORIO: applica la proprietà color-scheme all'elemento html o alla pseudo-classe :root. I browser cercano specificamente l'elemento root per determinare il tema dell'intera area visibile, incluse le barre di scorrimento root e lo sfondo iniziale del "canvas". Se applicate solo a body, queste piattaforme UI globali potrebbero rimanere in modalità Luce perché body non controlla il contesto di rendering della finestra.

/* MANDATORY: Apply color-scheme to :root or html for viewport-wide theming */
:root {
  /* MANDATORY: Automatically adapt native UI to user system preferences */
  color-scheme: light dark;
}

3. Definisci i token di colore chiaro e scuro

Puoi utilizzare la funzione light-dark() per definire token di colore che si adattano automaticamente ai diversi valori di color-scheme.

Ti consigliamo di conservare anche i valori dei colori non elaborati in proprietà personalizzate separate, in modo da poterli combinare più facilmente in modi diversi (e semplificare il comportamento di riserva, se necessario).

Per un maggiore controllo sui colori della UI integrata, come accent-color o scrollbar-color, gli autori possono facoltativamente aggiungere i propri colori dinamici utilizzando proprietà personalizzate e/o la funzione light-dark(). Questa funzione sceglie automaticamente il colore corretto in base al valore color-scheme calcolato dell'elemento ed elimina la necessità di query supporti ridondanti, ma non è obbligatoria per un'implementazione di base.

:root {
  --color-brand-light: oklch(45% 0.23 270);
  --color-brand-dark: oklch(85% 0.15 210);
  --color-brand-text-light: white;
  --color-brand-text-dark: oklch(40% 0.23 270);

  --color-brand: light-dark(var(--color-brand-light), var(--color-brand-dark));
  --color-brand-text: light-dark(var(--color-brand-text-light), var(--color-brand-text-dark));

  /* MANDATORY: Automatically adapt native UI to user system preferences */
  color-scheme: light dark;
}

button.primary {
  /* These automatically adapt to color scheme */
  background-color: var(--color-brand);
  color: var(--color-brand-text);
}

FACOLTATIVO: sono disponibili diversi colori di sistema, che si adattano automaticamente anche alla combinazione di colori utilizzata (e ad altre modalità di colore, ad esempio i colori forzati), come canvas, canvastext, accentcolor (verifica il supporto) , buttonborder e così via. In genere sono troppo limitati per essere utili, se non in casi molto specifici in cui è necessario abbinare esattamente una determinata UI del browser predefinito o come valori di riserva/predefiniti.

FACOLTATIVO: adatta le coppie di colori al contesto

Anche quando esegui l'override dell'impostazione predefinita del sistema, può essere utile utilizzare la query supporti prefers-color-scheme per definire coppie di colori diverse che tengano conto dei colori del browser e di Chrome OS intorno alla pagina (o della pagina circostante, quando la pagina viene utilizzata come iframe).

Ad esempio, utilizza un tema chiaro leggermente più scuro quando l'impostazione di sistema è dark o un tema scuro più contrastante quando l'impostazione di sistema è light, in modo che la pagina non venga sovrastata visivamente dalla UI circostante.

Personalizzazione granulare della UI del browser

L'impostazione di color-scheme adatta già l'interfaccia utente del browser alla combinazione di colori utilizzata, ma utilizzerà i valori predefiniti del sistema operativo e/o i colori di sistema che potrebbero non essere perfettamente in linea con il design del sito web. I browser moderni espongono diversi hook di personalizzazione granulari per questi elementi. Non reimplementare i controlli nativi semplicemente per personalizzarne l'aspetto senza aver prima esaurito gli hook di personalizzazione forniti dai browser moderni.

Impostazione del colore intenso

Alcuni elementi della UI del browser (ad es. caselle di controllo selezionate o cursori) utilizzano un colore intenso. Per impostazione predefinita, questa proprietà viene risolta nell'impostazione del sistema operativo, ma puoi utilizzare la proprietà accent-color per impostarla su un colore che si allinea meglio alla pagina, ad esempio il colore del brand della pagina.

html {
  accent-color: light-dark(var(--color-accent-light), var(--color-accent-dark));
}

Problemi da tenere presenti quando si utilizza accent-color

Il rendering del browser di accent-color varia. Per gli indicatori generalmente dipinti su uno sfondo di colore intenso, come i segni di spunta delle caselle di controllo e i punti dei pulsanti di opzione, i browser possono applicare trattamenti diversi:

  • Chromium e Firefox in genere selezionano un colore dell'indicatore a contrasto.
  • Safari potrebbe invece mantenere un indicatore bianco in modalità Luce o un indicatore nero in modalità Buio, modificando il colore intenso dietro di esso. Questa regolazione non fornisce sempre un contrasto sufficiente per ogni colore fornito, quindi testa le combinazioni importanti in Safari, incluse le combinazioni di colori chiari e scuri. Non dare per scontato che Safari scelga automaticamente il colore dell'indicatore che offre il contrasto migliore.

Colori della barra di scorrimento

Puoi utilizzare scrollbar-color insieme a light-dark() per impostare colori personalizzati della barra di scorrimento che si adattano alla combinazione di colori utilizzata.

:root {
  --color-scrollbar-track: light-dark(#eee, #222);
  --color-scrollbar-thumb: light-dark(#999, #666);
  scrollbar-color: var(--color-scrollbar-thumb) var(--color-scrollbar-track);
}

Problemi da tenere presenti quando si utilizza scrollbar-color

  • NON animare o applicare transizioni a scrollbar-color. Un bug di WebKit fa lampeggiare la barra di scorrimento ogni volta che scrollbar-color cambia.
  • Su macOS, le proprietà scrollbar-color (standard) e ::-webkit-scrollbar (legacy) vengono ignorate per impostazione predefinita perché macOS utilizza barre di scorrimento "overlay" native. DEVI accoppiare i colori personalizzati con scrollbar-width (ad es. thin o auto) per forzare macOS a eseguirne il rendering.
  • Anche con l'applicazione di scrollbar-width, le barre di scorrimento in overlay di macOS mostrano la barra (gutter) come trasparente per impostazione predefinita. Se il design richiede un colore di sfondo visibile della barra di scorrimento su MacOS, DEVI applicare scrollbar-gutter: stable; al contenitore scorrevole, ma tieni presente che viene visualizzato solo dopo che l'utente passa il mouse sopra la barra di scorrimento.
  • Anche con scrollbar-gutter: stable, la traccia potrebbe essere trasparente su MacOS. Il cursore non deve dipendere dal colore della barra per essere visibile.

Ulteriore personalizzazione

La maggior parte delle UI dei browser espone pseudo-elementi per personalizzare completamente il suo aspetto, ad esempio:

  • ::placeholder
  • ::spelling-error
  • ::grammar-error
  • ::selection
  • ::search-text
  • ::target-text
  • ::file-selector-button

Puoi utilizzare i colori light-dark() su uno qualsiasi di questi elementi per applicare colori che si adattano alla combinazione di colori utilizzata.

4. Immagini diverse per le modalità Luce e Buio

Per le immagini CSS, light-dark() può essere utilizzato anche per fornire valori di immagine diversi.

IMPORTANTE: entrambi i valori in light-dark() devono essere dello stesso tipo. Non puoi combinare un colore con un'immagine. Se uno dei due deve essere un'immagine, utilizza image(<color>) per aggregare il valore del colore.

Rilevamento del tema basato su JS

La maggior parte delle ramificazioni della combinazione di colori deve essere eseguita in CSS, che si adatta automaticamente alle modifiche.

Qualsiasi JS che legge matchMedia("(prefers-color-scheme: dark)").matches DEVE anche gestire il relativo evento change, poiché la preferenza di sistema può cambiare in qualsiasi momento.

FACOLTATIVO: implementazione di un pulsante di attivazione/disattivazione della combinazione di colori

Se vuoi consentire agli utenti di eseguire l'override manuale dell'impostazione predefinita di sistema per questo sito, puoi implementare un pulsante di attivazione/disattivazione della modalità Buio. La maggior parte dei siti non richiede un pulsante di attivazione/disattivazione permanente nella UI del sito. In genere è sufficiente utilizzare la combinazione di colori predefinita del sistema, eventualmente con un'impostazione in una superficie di impostazioni separata. Consulta la sezione Attivatori della modalità Buio per le best practice relative all'implementazione di un attivatore della modalità Buio (permanente o meno).

(FACOLTATIVO) Override specifici dei componenti

Puoi eseguire l'override del tema globale per elementi specifici impostando color-scheme su di essi.

Per ulteriori informazioni e suggerimenti, consulta Temi chiari/scuri specifici per i componenti.

Problemi noti di cui essere a conoscenza

Problemi da tenere presenti quando si utilizza color-scheme

  • Chrome e Firefox rispettano color-scheme per gli iframe: eseguono il rendering delle pagine incorporate nella combinazione di colori corretta e regolano la query supporti prefers-color-scheme della pagina incorporata in modo che rifletta color-scheme del contesto di incorporamento. Safari non lo fa e risolve prefers-color-scheme nell'impostazione di sistema anche all'interno degli iframe.
    • Se controlli sia l'elemento principale che l'iframe: passa esplicitamente la combinazione di colori dell'elemento principale all'iframe tramite un parametro URL (?theme=dark) al momento della creazione dell'iframe o tramite postMessage() (che ti consente anche di reagire alle modifiche di runtime). Nell'iframe, imposta una classe su <html> (e/o color-scheme su :root) da quell'indicatore anziché fare affidamento su prefers-color-scheme.
    • Se controlli solo la pagina incorporata: non esiste un modo affidabile per rilevare il color-scheme del contesto di incorporamento dall'interno dell'iframe in Safari. Esponi un parametro del tema esplicito nell'API di incorporamento (ad esempio una stringa di query o un protocollo postMessage) e documentalo per gli incorporatori.

Strategie di riserva

Alternative e supporto del browser per color-scheme

La proprietà color-scheme è un potenziamento progressivo. I browser che non la supportano ignoreranno questa proprietà e utilizzeranno la UI predefinita della modalità Luce.

Per adattarti alle preferenze dell'utente nei browser meno recenti, utilizza le query supporti prefers-color-scheme per fornire colori diversi quando è preferita la modalità Buio.

  • Utilizza la query supporti per attivare le proprietà personalizzate su :root o html
  • Evita di utilizzare la query supporti su singoli componenti, a meno che il componente non richieda un tipo molto specifico di personalizzazione della modalità Buio oltre ai colori.
:root {
  /* Define brand colors for each mode */
  --color-brand-light: #0056b3;
  --color-brand-dark: #00e5ff;
  --color-brand: var(--color-brand-light);

  /* MANDATORY: Fallback for browsers without light-dark support */
  @media (prefers-color-scheme: dark) {
    --color-brand: var(--color-brand-dark);
  }

  /* Ignored in older browsers */
  color-scheme: light dark;
}

button.primary {
    background-color: var(--color-brand);
}

Alternative e supporto del browser per light-dark()

Per i browser che supportano color-scheme, ma non ancora light-dark(), le versioni chiare e scure dei colori devono essere prima definite come proprietà personalizzate e la query supporti prefers-color-scheme deve essere utilizzata per impostare i colori per la rispettiva modalità, come nell'esempio seguente:

:root {
  /* Define browser UI accent color for each mode */
  --brand-accent-light: #0056b3;
  --brand-accent-dark: #00e5ff;
  --accent-color: var(--brand-accent-light);

  /* MANDATORY: Fallback for browsers without light-dark support */
  @media (prefers-color-scheme: dark) {
    --accent-color: var(--brand-accent-dark);
  }

  /* OPTIONAL: use light-dark() for more control of built-in UI colors */
  @supports (color: light-dark(white, black)) {
    --accent-color: light-dark(var(--brand-accent-light), var(--brand-accent-dark));
  }

  /* MANDATORY: Automatically adapt native UI to user system preferences */
  color-scheme: light dark;

  /* Example inherited color property */
  accent-color: var(--accent-color);
}

pre, code {
  color-scheme: dark;

  /* **Mandatory**: any inherited color properties must be set again, even if to the same design tokens */
  accent-color: var(--accent-color);
}

Valori di riserva e supporto del browser per i valori delle immagini light-dark()

Per i browser che non supportano light-dark() per le immagini, utilizza image-set() come opzione: assegna a ogni opzione un type() da una proprietà personalizzata e imposta quella non attiva su un tipo MIME non supportato in modo che il browser la ignori. L'opzione attiva riceve un valore vuoto, quindi è una semplice opzione image-set() senza type().

Definisci il sensore una volta su :root. In ogni sito di utilizzo, quindi, è necessario solo che entrambe le immagini siano incorporate, ad esempio light-dark().

:root {
  --light-type: ;
  --dark-type: type("image/do-not-use");

  /* MANDATORY: Fallback for browsers without light-dark() image support */
  @media (prefers-color-scheme: dark) {
    --light-type: type("image/do-not-use");
    --dark-type: ;
  }
}

.hero {
  background-image: image-set(url(hero-light.png) var(--light-type), url(hero-dark.png) var(--dark-type));

  @supports (background-image: light-dark(url("a"), url("b"))) {
    background-image: light-dark(url(hero-light.png), url(hero-dark.png));
  }
}
  • Viene scaricata solo l'immagine selezionata.
  • Risoluzioni ancora valide: image-set(url(a-1x.png) 1x var(--light-type), url(a-2x.png) 2x var(--light-type), url(b-1x.png) 1x var(--dark-type), url(b-2x.png) 2x var(--dark-type)).
  • NON utilizzare type("") per l'opzione attiva. I browser considerano la stringa vuota come non supportata e ignorano ogni opzione.
  • A differenza di light-dark(), l'opzione non segue color-scheme impostato su un sottoalbero. Un pulsante di attivazione/disattivazione manuale o qualsiasi sottoalbero che imposta color-scheme DEVE anche invertire --light-type e --dark-type.

Alternativa: una proprietà personalizzata per immagine

È più semplice quando variano solo poche immagini, ma ogni immagine richiede il proprio ramo di query supporti e un'attivazione manuale per ciascuna.

:root {
  --hero-image: url(hero-light.png);

  @media (prefers-color-scheme: dark) {
    --hero-image: url(hero-dark.png);
  }

  @supports (background-image: light-dark(url("a"), url("b"))) {
    --hero-image: light-dark(url(hero-light.png), url(hero-dark.png));
  }
}

.hero {
  background-image: var(--hero-image);
}

Immagini di riserva e supporto del browser per image()

Utilizza un gradiente con un singolo punto di colore e senza posizioni, ad esempio linear-gradient(blue).

Per un supporto più ampio del browser, puoi fornire esplicitamente le posizioni 0 100% per il singolo punto di colore, ad esempio linear-gradient(blue 0 100%).

Alternative e supporto del browser per scrollbar-color

Questa funzionalità è un potenziamento progressivo e non richiede sempre i fallback.

Se lo stile è importante e il target Baseline dell'utente è "Baseline ampiamente disponibile" o precedente, DEVI includere gli pseudo-elementi ::-webkit-scrollbar non standard come fallback.

Racchiudi i fallback legacy in un blocco @supports not (scrollbar-color: auto) per evitare conflitti tra le proprietà standard e i selettori WebKit legacy nei browser che supportano entrambi in modo nativo.

Se utilizzi proprietà personalizzate per definire i colori, questi verranno applicati automaticamente ai selettori WebKit legacy. NON è necessario duplicarli.

/* Legacy fallback for WebKit/Blink browsers */
@supports not (scrollbar-color: auto) {
  .scroller::-webkit-scrollbar {
    /* Must define base size in WebKit for custom colors to be visual */
    width: 12px;
    height: 12px;
  }

  .scroller::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
  }

  .scroller::-webkit-scrollbar-track {
    background: var(--scrollbar-track);
  }
}

Alternative e supporto dei browser per accent-color

La proprietà accent-color è un potenziamento progressivo. I browser che non supportano questa proprietà la ignoreranno e utilizzeranno i colori predefiniti della UI.