# Créer un thème avec les variables CSS : clair, sombre et marque

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

Les thèmes déraillent quand les couleurs sont nommées d’après leur aspect plutôt que leur rôle. Nommez les rôles, reliez-les à une palette, et mode clair, mode sombre et seconde marque tiennent en quelques lignes chacun.

## The short version

- Un thème en variables CSS fonctionne mieux en deux couches : des variables de palette qui contiennent les couleurs brutes et des variables sémantiques qui décrivent l’usage de chaque couleur.
- Les composants ne doivent jamais lire que des variables sémantiques comme --color-text ou --color-surface, jamais directement les valeurs de la palette.
- Le mode sombre consiste alors à faire pointer les variables sémantiques vers d’autres valeurs de la palette, dans une media query ou sous un attribut data.
- La fonction light-dark() et la propriété color-scheme permettent à une seule déclaration de contenir les deux modes dans les navigateurs actuels.
- Un petit script en ligne dans le head, qui applique le thème enregistré avant l’affichage de la page, évite le flash du mauvais thème.

Un **thème en variables CSS** est un ensemble de propriétés personnalisées, comme `--color-surface` et `--color-text`, que chaque composant lit au lieu de couleurs codées en dur. Pour changer de thème, vous changez les variables, en général sur `:root` ou sur un attribut `data-theme`, et toute l’interface suit. L’astuce qui permet de passer à l’échelle consiste à répartir les variables en deux couches : une palette de couleurs brutes, et des rôles sémantiques qui pointent vers cette palette.

## Deux couches : la palette et les rôles

Les variables de palette sont nommées d’après ce qu’elles sont : `--violet-600`, `--ink-900`. Les variables sémantiques sont nommées d’après ce qu’elles font : `--color-accent`, `--color-text-muted`. Les composants ne lisent que les secondes. Quand le mode sombre arrive, vous redirigez les rôles et ne touchez à aucun composant. C’est la même idée que [les design tokens](https://gradiently.design/fr/guide/design-tokens), exprimée directement en CSS.

| Couche | Exemple | Qui la lit | Change quand |
| --- | --- | --- | --- |
| Palette | `--violet-600: #7c3aed` | Seulement la couche des rôles | La marque est redessinée |
| Rôle | `--color-accent: var(--violet-600)` | Tous les composants | Le thème ou le mode change |
| Composant | `--button-bg: var(--color-accent)` | Un seul composant | Un composant a besoin d’une variante locale |

La couche composant est facultative. Ne l’utilisez que là où un composant doit vraiment s’écarter du rôle.

```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); }
```

Les composants ne mentionnent jamais violet ni ink. Cette seule règle rend le thème interchangeable.

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

Les rôles du thème clair. Un fond papier chaud plutôt qu’un blanc pur rend l’accent violet plus calme.

### Nommer des rôles qui survivent à une refonte

Un nom de rôle doit rester vrai après le changement des couleurs. `--light-grey` cesse d’être clair en mode sombre, et `--blue` ment le jour où la marque passe au vert. Nommez plutôt la fonction et l’association, pour que la prochaine personne qui lira la feuille de style sache quelle couleur va sur laquelle.

### Des noms qui cassent

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

### Des noms qui durent

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

## Ajouter le mode sombre avec les variables CSS

Le mode sombre redirige les rôles. Respectez par défaut le réglage du système d’exploitation, et laissez un attribut `data-theme` le remplacer quand le lecteur fait un choix. Définissez aussi `color-scheme`, pour que barres de défilement, contrôles de formulaire et fond par défaut s’accordent.

```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);
}
```

Les valeurs sombres apparaissent deux fois : une pour la préférence système, une pour un choix explicite. Un mixin de préprocesseur ou `light-dark()` supprime la répétition.

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

Les rôles du thème sombre. L’accent passe à un violet plus clair, car le violet du mode clair est trop sombre pour se lire sur un fond presque noir.

Le mode sombre n’est pas le mode clair inversé. Les surfaces s’éclaircissent à mesure qu’elles s’élèvent, les accents s’éclaircissent, et les ombres cèdent la place aux bordures. [Le design en mode sombre](https://gradiently.design/fr/guide/dark-mode-design) et [les dégradés en mode sombre](https://gradiently.design/fr/guide/dark-mode-gradients) traitent du côté visuel.

### Le raccourci light-dark()

Les navigateurs actuels prennent en charge `light-dark()`, qui reçoit une valeur claire et une valeur sombre et choisit selon le `color-scheme` de l’élément. Définissez `color-scheme: light dark` sur la racine pour suivre le système, ou imposez-en un avec l’attribut, et chaque rôle tient en une ligne : `--color-bg: light-dark(var(--paper-50), var(--night-950))`. Gardez la forme longue si vous devez prendre en charge des navigateurs antérieurs à 2024.

## Une bascule de thème qui ne clignote pas

Si le choix enregistré est appliqué après l’affichage de la page, les lecteurs qui ont choisi le sombre voient un flash blanc à chaque chargement. Définissez l’attribut dans un minuscule script en ligne dans le `head`, avant qu’aucune feuille de style ne peigne le 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>
```

S’exécute avant le premier affichage. Le bouton de bascule n’a plus qu’à définir `dataset.theme` et enregistrer la valeur dans `localStorage`.

1. **Proposez trois choix** Clair, sombre et système. Retirer l’attribut rend la main à `prefers-color-scheme`.
2. **N’enregistrez que les choix explicites** Stockez `light` ou `dark` ; supprimez la clé pour système, afin qu’un changement ultérieur dans le système d’exploitation soit respecté.
3. **Évitez les transitions au chargement** Si les couleurs sont animées, n’activez la transition qu’après le premier affichage, sinon la page s’anime du clair au sombre en se chargeant.

## Des thèmes de marque au-delà du clair et du sombre

Les deux mêmes couches gèrent plusieurs marques dans une seule base de code. Chaque marque fournit sa propre palette et ses valeurs de rôles sous un attribut `data-brand`, et les modes fonctionnent toujours par-dessus. Avec `color-mix()`, vous pouvez dériver états de survol et teintes claires d’un seul accent par marque, comme le montre [color-mix() en CSS](https://gradiently.design/fr/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); }
```

Les dégradés peuvent aussi être des tokens. Stockez toute la valeur dans une variable et l’en-tête change avec la marque.

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

Les deux tokens d’en-tête du code ci-dessus. Même structure, même angle, autre marque.

Comme les propriétés personnalisées s’héritent, un thème n’a pas à couvrir toute la page. Placez `data-theme="dark"` sur une section, comme un bandeau promotionnel ou un pied de page, et tout ce qu’elle contient lit les rôles sombres tandis que le reste de la page reste clair. Écrivez le sélecteur sombre `[data-theme="dark"]` plutôt que `:root[data-theme="dark"]` pour que cela fonctionne, et définissez aussi `color-scheme` sur la section.

> **Les dégradés ne s’animent pas seuls** Changer une variable de dégradé remplace l’arrière-plan instantanément. Pour animer le passage d’un dégradé à un autre, déclarez les arrêts de couleur avec `@property`, comme l’explique [@property en CSS](https://gradiently.design/fr/guide/css-property-animation).

## Gardez le web et vos créations sur une même palette

Un thème CSS n’est que la moitié d’une marque. Les mêmes couleurs devraient apparaître dans vos publications sociales, présentations et e-mails. Le kit de marque de Gradiently contient vos palettes, vos logos et vos polices de titre et de texte, et le Designer l’applique quand il compose une création : la publication que vous faites lundi utilise le même accent que votre site. Si vous choisissez encore ces couleurs, commencez par [comment choisir les couleurs de sa marque](https://gradiently.design/fr/guide/how-to-choose-brand-colors).

## FAQ

### Comment créer un thème avec les variables CSS ?

Définissez des variables de palette avec les couleurs brutes, puis des variables sémantiques comme `--color-bg` qui pointent vers elles. Les composants ne lisent que les sémantiques, et les thèmes les redirigent.

### Comment ajouter un mode sombre avec les variables CSS ?

Redéfinissez les variables sémantiques dans `@media (prefers-color-scheme: dark)` et sous un sélecteur `[data-theme="dark"]` pour les lecteurs qui le choisissent.

### Comment éviter que le thème clignote au chargement ?

Lisez le thème enregistré dans un petit script en ligne dans le `head` et définissez l’attribut avant que la feuille de style ne peigne la page.

### Que fait light-dark() en CSS ?

Elle renvoie sa première valeur en mode clair et la seconde en mode sombre, selon le `color-scheme` de l’élément. Elle fonctionne dans les grands navigateurs actuels.

### Peut-on stocker un dégradé dans une variable CSS ?

Oui. Stockez tout le dégradé comme valeur et utilisez-le dans `background`. Pour animer le passage d’un dégradé à l’autre, déclarez les arrêts avec `@property`.
