# Tema con variabili CSS: modalità chiara, scura e colori del brand

[Canonical HTML page](https://gradiently.design/it/guide/css-custom-properties-theming)

I temi si rompono quando i colori prendono il nome da come appaiono invece che da ciò che fanno. Dai un nome ai ruoli, puntali a una palette, e modalità chiara, scura e un secondo brand diventano poche righe ciascuno.

## The short version

- Un tema con variabili CSS funziona meglio su due livelli: variabili di palette che contengono i colori grezzi e variabili semantiche che descrivono a cosa serve ogni colore.
- I componenti dovrebbero leggere solo variabili semantiche come --color-text o --color-surface, mai i valori della palette direttamente.
- La modalità scura diventa allora questione di puntare le variabili semantiche a valori diversi della palette, con una media query o un attributo data.
- La funzione light-dark() e la proprietà color-scheme permettono a una sola dichiarazione di contenere entrambe le modalità nei browser attuali.
- Un piccolo script inline nell'head che imposta il tema salvato prima del rendering della pagina evita il lampo del tema sbagliato.

Un **tema con variabili CSS** è un insieme di proprietà personalizzate, come `--color-surface` e `--color-text`, che ogni componente legge al posto di colori scritti a mano. Per cambiare tema cambi le variabili, di solito su `:root` o su un attributo `data-theme`, e tutta l'interfaccia le segue. Il trucco che lo rende scalabile è dividere le variabili in due livelli: una palette di colori grezzi e ruoli semantici che puntano a quella palette.

## Due livelli: palette e ruoli

Le variabili di palette prendono il nome da ciò che sono: `--violet-600`, `--ink-900`. Le variabili semantiche prendono il nome da ciò che fanno: `--color-accent`, `--color-text-muted`. I componenti leggono solo le seconde. Quando arriva la modalità scura, riassegni i ruoli e lasci intatti i componenti. È la stessa idea dei [design token](https://gradiently.design/it/guide/design-tokens), espressa direttamente in CSS.

| Livello | Esempio | Chi lo legge | Cambia quando |
| --- | --- | --- | --- |
| Palette | `--violet-600: #7c3aed` | Solo il livello dei ruoli | Il brand viene ridisegnato |
| Ruolo | `--color-accent: var(--violet-600)` | Ogni componente | Cambia il tema o la modalità |
| Componente | `--button-bg: var(--color-accent)` | Un solo componente | Un singolo componente ha bisogno di una variante locale |

Il livello dei componenti è facoltativo. Usalo solo dove un componente deve davvero distinguersi dal ruolo.

```css
:root {
  /* Palette: raw values, named for what they are */
  --paper-50: #faf8f5;
  --paper-100: #f1ede6;
  --ink-900: #14121f;
  --ink-700: #3d3a4f;
  --ink-500: #6b6880;
  --violet-600: #6d28d9;
  --violet-300: #c4b5fd;
  --night-950: #0d0b16;
  --night-900: #17142a;
  --night-800: #221e3a;

  /* Roles: what each colour is for (light mode) */
  --color-bg: var(--paper-50);
  --color-surface: var(--paper-100);
  --color-text: var(--ink-900);
  --color-text-muted: var(--ink-500);
  --color-border: color-mix(in oklab, var(--ink-900) 12%, transparent);
  --color-accent: var(--violet-600);
  --color-on-accent: #ffffff;
}

body { background: var(--color-bg); color: var(--color-text); }
.card { background: var(--color-surface); border: 1px solid var(--color-border); }
.button { background: var(--color-accent); color: var(--color-on-accent); }
```

I componenti non nominano mai viola o inchiostro. Questa sola regola rende il tema intercambiabile.

- bg: #faf8f5
- surface: #f1ede6
- text: #14121f
- text-muted: #6b6880
- accent: #6d28d9

I ruoli del tema chiaro. Un fondo color carta calda al posto del bianco puro rende l'accento viola più calmo.

### Dare ai ruoli nomi che sopravvivono a un restyling

Il nome di un ruolo dovrebbe restare vero anche dopo che i colori cambiano. `--light-grey` smette di essere chiaro in modalità scura, e `--blue` mente il giorno in cui il brand diventa verde. Dai un nome al compito e all'abbinamento, così chi legge il foglio di stile dopo di te sa quale colore va su quale.

### Nomi che si rompono

- `--blue`, `--purple-button`
- `--light-grey-bg`
- `--white-text`
- `--dark-border`

### Nomi che durano

- `--color-accent`, `--color-on-accent`
- `--color-surface`
- `--color-text`
- `--color-border`

## Aggiungere la modalità scura con le variabili CSS

La modalità scura riassegna i ruoli. Rispetta per impostazione predefinita la preferenza del sistema operativo e lascia che un attributo `data-theme` la sostituisca quando chi legge sceglie. Imposta anche `color-scheme`, così barre di scorrimento, controlli dei moduli e tela predefinita si adattano.

```css
:root { color-scheme: light; }

/* Follow the system unless the reader picked light */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --color-bg: var(--night-950);
    --color-surface: var(--night-900);
    --color-text: #f2f0fa;
    --color-text-muted: #a5a1bd;
    --color-border: color-mix(in oklab, #ffffff 12%, transparent);
    --color-accent: var(--violet-300);
    --color-on-accent: var(--ink-900);
  }
}

/* The reader picked dark explicitly */
:root[data-theme="dark"] {
  color-scheme: dark;
  --color-bg: var(--night-950);
  --color-surface: var(--night-900);
  --color-text: #f2f0fa;
  --color-text-muted: #a5a1bd;
  --color-border: color-mix(in oklab, #ffffff 12%, transparent);
  --color-accent: var(--violet-300);
  --color-on-accent: var(--ink-900);
}
```

I valori scuri compaiono due volte: una per la preferenza di sistema e una per la scelta esplicita. Un mixin del preprocessore o `light-dark()` elimina la ripetizione.

- bg: #0d0b16
- surface: #17142a
- text: #f2f0fa
- text-muted: #a5a1bd
- accent: #c4b5fd

I ruoli del tema scuro. L'accento sale a un viola più chiaro, perché il viola della modalità chiara è troppo scuro da leggere su un fondo quasi nero.

La modalità scura non è la modalità chiara invertita. Le superfici si schiariscono man mano che salgono, gli accenti si illuminano e le ombre lasciano il posto ai bordi. [Il design in modalità scura](https://gradiently.design/it/guide/dark-mode-design) e [i gradienti in modalità scura](https://gradiently.design/it/guide/dark-mode-gradients) trattano l'aspetto visivo.

### La scorciatoia light-dark()

I browser attuali supportano `light-dark()`, che prende un valore chiaro e uno scuro e ne sceglie uno in base al `color-scheme` dell'elemento. Imposta `color-scheme: light dark` sulla radice per seguire il sistema, oppure forza una modalità con l'attributo, e ogni ruolo diventa una sola riga: `--color-bg: light-dark(var(--paper-50), var(--night-950))`. Mantieni la forma più lunga se devi supportare browser precedenti al 2024.

## Un selettore di tema che non lampeggia

Se la scelta salvata viene applicata dopo il rendering della pagina, chi ha scelto la modalità scura vede un lampo bianco a ogni caricamento. Imposta l'attributo in un minuscolo script inline nell'`head`, prima che qualsiasi foglio di stile dipinga il body.

```html
<head>
  <script>
    (function () {
      var saved = localStorage.getItem("theme");
      if (saved === "light" || saved === "dark") {
        document.documentElement.dataset.theme = saved;
      }
    })();
  </script>
  <link rel="stylesheet" href="/styles.css">
</head>
```

Gira prima del primo rendering. Il pulsante di selezione deve poi solo impostare `dataset.theme` e salvare il valore in `localStorage`.

1. **Offri tre scelte** Chiaro, scuro e sistema. Rimuovendo l'attributo il controllo torna a `prefers-color-scheme`.
2. **Salva solo le scelte esplicite** Memorizza `light` o `dark`; elimina la chiave per «sistema», così un cambiamento successivo nel sistema operativo viene rispettato.
3. **Evita le transizioni al caricamento** Se i colori hanno una transizione, abilitala solo dopo il primo rendering, altrimenti la pagina anima dal chiaro allo scuro mentre si carica.

## Temi di brand oltre chiaro e scuro

Gli stessi due livelli gestiscono più brand in un solo codice. Ogni brand fornisce la propria palette e i propri valori dei ruoli sotto un attributo `data-brand`, e le modalità continuano a funzionare sopra. Con `color-mix()` puoi ricavare stati hover e tinte da un solo accento per brand, come mostrato in [color-mix() in CSS](https://gradiently.design/it/guide/css-color-mix).

```css
[data-brand="harbour"] {
  --color-accent: #0f766e;
  --gradient-hero: linear-gradient(150deg, #042f2e 0%, #0f766e 55%, #5eead4 100%);
}

[data-brand="ember"] {
  --color-accent: #c2410c;
  --gradient-hero: linear-gradient(150deg, #431407 0%, #c2410c 55%, #fdba74 100%);
}

.button:hover { background: color-mix(in oklab, var(--color-accent), black 12%); }
.hero { background: var(--gradient-hero); }
```

Anche i gradienti possono essere token. Salva l'intero valore in una variabile e l'hero cambia con il brand.

- Hero Harbour: `linear-gradient(150deg, #042f2e 0%, #0f766e 55%, #5eead4 100%)`
- Hero Ember: `linear-gradient(150deg, #431407 0%, #c2410c 55%, #fdba74 100%)`

I due token hero del codice qui sopra. Stessa struttura, stesso angolo, brand diverso.

Poiché le proprietà personalizzate si ereditano, un tema non deve coprire l'intera pagina. Metti `data-theme="dark"` su una sola sezione, come una fascia promozionale o un footer, e tutto ciò che contiene legge i ruoli scuri mentre il resto della pagina resta chiaro. Scrivi il selettore scuro come `[data-theme="dark"]` invece di `:root[data-theme="dark"]` se vuoi che funzioni, e imposta `color-scheme` anche sulla sezione.

> **I gradienti non fanno transizione da soli** Cambiare una variabile di gradiente sostituisce lo sfondo all'istante. Per animare tra due gradienti, registra i punti colore con `@property`, spiegato in [CSS @property](https://gradiently.design/it/guide/css-property-animation).

## Web e design sulla stessa palette

Un tema in CSS è solo metà di un brand. Gli stessi colori dovrebbero comparire nei tuoi post social, nelle presentazioni e nelle email. Il brand kit di Gradiently contiene le tue palette, i loghi e i font per titoli e testo, e il Designer lo applica quando imposta un design, così il post che crei il lunedì usa lo stesso accento del tuo sito. Se stai ancora scegliendo quei colori, parti da [come scegliere i colori del brand](https://gradiently.design/it/guide/how-to-choose-brand-colors).

## FAQ

### Come creo un tema con le variabili CSS?

Definisci variabili di palette con i colori grezzi, poi variabili semantiche come `--color-bg` che puntano a esse. I componenti leggono solo quelle semantiche e i temi le riassegnano.

### Come aggiungo la modalità scura con le variabili CSS?

Sostituisci le variabili semantiche dentro `@media (prefers-color-scheme: dark)` e sotto un selettore `[data-theme="dark"]` per chi sceglie la modalità scura.

### Come evito che il tema lampeggi al caricamento della pagina?

Leggi il tema salvato in un piccolo script inline nell'`head` e imposta l'attributo prima che il foglio di stile dipinga la pagina.

### Cosa fa light-dark() in CSS?

Restituisce il primo valore in modalità chiara e il secondo in modalità scura, in base al `color-scheme` dell'elemento. Funziona nei principali browser attuali.

### Posso salvare un gradiente in una variabile CSS?

Sì. Salva l'intero gradiente come valore e usalo in `background`. Per animare tra gradienti, registra i punti colore con `@property`.
