L’essentiel en bref
- 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.
Sur cette page
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, exprimée directement en CSS.
--violet-600: #7c3aedQui la lit
Change quand
--color-accent: var(--violet-600)Qui la lit
Change quand
Exemple
--button-bg: var(--color-accent)Qui la lit
Change quand
: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); }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.
: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);
}light-dark() supprime la répétition.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 et les dégradés en mode sombre 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.
<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>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
lightoudark; 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.
[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); }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.
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.
Les questions qu’on nous pose
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.
Écrit par Gradiently
L’équipe derrière Gradiently, un outil de création construit autour des Marks : des dégradés vivants qui donnent à tout ce que vous créez votre propre signature.
Voir notre profil