DonnIA
Toutes les ressources
GuideFondamentaux IA13 min

Jetons de design et thème sombre

Poser une palette en variables CSS nommées par rôle, et obtenir un thème sombre sans une seule couleur en dur.


Le thème sombre révèle toujours la même chose : la couleur est écrite en dur un peu partout. On croit avoir trois couleurs, on en trouve quarante. Le gris du texte a onze variantes, dont neuf sont des accidents.

Ajouter un thème sombre sur cette base, c'est dupliquer quarante valeurs et maintenir deux fois le même désordre. La bonne séquence est inverse : d'abord mettre de l'ordre, ensuite le thème sombre devient une vingtaine de lignes.

Ce guide décrit cet ordre : nommer les couleurs par leur rôle, les poser en variables CSS, puis basculer la définition sans jamais toucher aux composants.

Avant de commencer

  • Un projet avec du CSS, quelle que soit la façon dont il est écrit
  • Une feuille de style globale où poser les variables
  • Une heure, plus le temps de relecture

1Faire l'inventaire avant de décider quoi que ce soit

Tu ne peux pas ranger ce que tu n'as pas compté. Demande le relevé :

Liste toutes les valeurs de couleur ecrites en dur dans le projet
(hexadecimal, rgb, hsl, oklch), avec pour chacune le fichier, la ligne et
le nombre d'occurrences. Trie par frequence. Ne modifie rien.

Le résultat est presque toujours instructif : trois ou quatre valeurs dominantes, puis une longue traîne de variantes uniques qui sont des erreurs de copie. La traîne se ramène sur les valeurs dominantes.

Fais le même relevé sur les espacements, les rayons de bordure et les tailles de police. C'est le même problème, en moins visible.

2Nommer par rôle, pas par couleur

C'est la décision qui rend le thème sombre possible. Un composant ne doit pas savoir qu'il est bleu, il doit savoir qu'il est « la surface principale » ou « le texte secondaire ».

Nom à éviterNom qui survit au thème sombre
--bleu-500--couleur-accent
--gris-clair--surface-carte
--noir--texte-principal
--gris-moyen--texte-secondaire
--gris-tres-clair--bordure

Une palette de rôles utile tient en une dizaine d'entrées : fond de page, surface d'un bloc, texte principal, texte secondaire, bordure, accent, texte sur accent, et deux ou trois états (succès, avertissement, erreur).

Deux couches, pas une

Beaucoup de systèmes gardent deux niveaux : une palette brute (--bleu-500, --bleu-600) que personne n'utilise directement, et des rôles (--couleur-accent: var(--bleu-500)) que les composants consomment. Le premier niveau sert à changer de gamme, le second à changer de thème.

3Poser les variables

Tout se déclare une fois, sur la racine :

:root {
  color-scheme: light;

  --surface-page: #ffffff;
  --surface-carte: #f7f7f5;
  --texte-principal: #16151a;
  --texte-secondaire: #5b5966;
  --bordure: #e4e2dd;
  --accent: #5b3df5;
  --texte-sur-accent: #ffffff;
}

La déclaration color-scheme n'est pas décorative. Elle indique au navigateur dans quel schéma la page se rend, et il ajuste en conséquence les couleurs par défaut de la surface du document, des barres de défilement et des contrôles de formulaire. Ses valeurs sont normal, light, dark, light dark, et les formes only light et only dark qui interdisent au navigateur d'appliquer son propre forçage.

Sans elle, tu obtiens des menus déroulants blancs sur un site sombre.

4Basculer le thème

Deux mécanismes, à combiner.

La préférence système se lit avec prefers-color-scheme, dont les valeurs sont light et dark. Le choix explicite du visiteur se porte, lui, par un attribut ou une classe posée sur l'élément racine.

/* preference systeme */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --surface-page: #131217;
    --surface-carte: #1c1b22;
    --texte-principal: #f2f1ee;
    --texte-secondaire: #a5a2b0;
    --bordure: #2c2a35;
    --texte-sur-accent: #ffffff;
  }
}

/* choix explicite, qui doit gagner dans les deux sens */
:root[data-theme="dark"] {
  color-scheme: dark;
  --surface-page: #131217;
  /* ...les memes redefinitions */
}

Le point à ne pas rater : une couleur ne doit jamais avoir sa seule définition à l'intérieur d'un bloc @media ou d'un sélecteur de thème. La définition complète vit sur :root nu, les blocs suivants ne font que redéfinir.

Une alternative plus courte

La fonction CSS light-dark() prend deux valeurs et choisit selon le schéma courant : color: light-dark(#16151a, #f2f1ee). Elle exige que color-scheme soit défini, typiquement color-scheme: light dark sur :root. Elle est disponible dans les navigateurs récents (référencée comme Baseline depuis mai 2024) : si tu dois couvrir des navigateurs plus anciens, reste sur la requête de média.

5Vérifier les contrastes, thème par thème

Un thème sombre n'hérite pas des contrastes du thème clair. Le gris secondaire qui passait sur fond blanc peut échouer sur fond gris foncé.

Le seuil de référence est celui du critère WCAG 1.4.3, de niveau AA : 4,5:1 pour le texte courant, 3:1 pour le texte de grande taille, défini comme au moins 18 points, ou 14 points en gras. Les éléments d'interface et les indicateurs visuels relèvent du critère 1.4.11, à 3:1.

Ouvre la page en thème clair puis en thème sombre. Pour chaque couple
texte/fond distinct, calcule le rapport de contraste et rends-moi un
tableau : selecteur, couleurs, ratio, seuil applicable, conforme ou non.
Ne corrige rien.

Le piège de l'inversion mécanique

Inverser la luminosité de chaque couleur ne produit pas un bon thème sombre. Les grands aplats très clairs deviennent des aplats très foncés qui écrasent la page, et le blanc pur sur noir pur fatigue. En pratique, on descend rarement au noir absolu pour le fond, et on ne monte pas au blanc absolu pour le texte.

Le test qui dit si c'est fait

Change la valeur de --accent à un seul endroit. Si toute l'interface suit, boutons, liens, états de focus et bordures actives compris, le système existe. S'il reste des îlots à l'ancienne couleur, l'inventaire de l'étape 1 n'était pas complet.

Passe ensuite un dernier balayage :

Cherche toute valeur de couleur ecrite en dur qui subsiste dans les
composants, hors du fichier de variables. Liste fichier, ligne et valeur.

Quelques prompts pour aller plus loin

ObjectifPrompt à adapter
InventorierListe les couleurs en dur du projet, triees par frequence, avec fichier et ligne.
NommerPropose une liste de roles de couleur a partir de cet inventaire, avec le nom, l'usage et la valeur claire.
MigrerRemplace [VALEUR] par var(--[ROLE]) dans tout le projet, et liste les fichiers modifies.
Auditer un thèmePour le thème sombre, liste les couples texte/fond dont le ratio est sous 4,5:1, avec le ratio mesure.
Vérifier les contrôlesOuvre la page en thème sombre et dis-moi si les champs de formulaire, les listes deroulantes et les barres de defilement suivent le thème.

Tu as d’autres ressources comme ça ?

Ce que tu viens de lire est entièrement gratuit. Une nouvelle ressource part chaque semaine dans la newsletter : guides, modèles à copier et liens triés, sans compte à créer.

Cette page est en accès libre, n’hésite pas à la partager.