Variables CSS : Guide complet des custom properties en CSS

Si vous avez déjà travaillé sur une feuille de style CSS de plusieurs centaines de lignes, vous connaissez sans doute ce sentiment de frustration : modifier une couleur principale implique de chercher et remplacer cette valeur dans des dizaines d’endroits différents. Une erreur d’inattention, et c’est la catastrophe visuelle. Les variables CSS, aussi appelées custom properties, sont là pour résoudre définitivement ce problème.

Introduites comme fonctionnalité native des navigateurs modernes, les variables CSS permettent de stocker des valeurs réutilisables directement dans vos feuilles de style. Plus besoin de préprocesseurs comme SASS ou LESS pour bénéficier de cette puissance : tout se passe dans le CSS pur, avec en bonus la possibilité de les manipuler dynamiquement grâce à JavaScript.

Dans ce guide complet, nous allons explorer tout ce qu’il faut savoir sur les variables CSS : de leur syntaxe de base aux techniques avancées comme la création de thèmes sombres dynamiques, en passant par l’héritage, les valeurs de fallback et les bonnes pratiques de structuration. Que vous soyez débutant ou développeur expérimenté, vous repartirez avec des connaissances concrètes et applicables immédiatement.

Qu’est-ce qu’une variable CSS ?

Une variable CSS, officiellement appelée propriété personnalisée CSS (CSS custom property), est un mécanisme natif qui permet de définir une valeur une seule fois et de la réutiliser partout dans votre feuille de style. Elle fonctionne exactement comme une variable dans un langage de programmation classique : vous lui attribuez un nom et une valeur, puis vous la référencez chaque fois que vous en avez besoin.

Concrètement, une variable CSS se déclare avec un préfixe double tiret (--) et s’utilise via la fonction var(). Voici un exemple minimal :

:root {
  --couleur-principale: #3498db;
  --espacement-base: 16px;
  --police-titre: 'Montserrat', sans-serif;
}

h1 {
  color: var(--couleur-principale);
  font-family: var(--police-titre);
  margin-bottom: var(--espacement-base);
}

Dans cet exemple, modifier la valeur de --couleur-principale dans :root affectera automatiquement tous les éléments qui l’utilisent. Fini le Ctrl+H hasardeux dans un fichier de mille lignes.

Pourquoi utiliser les variables CSS plutôt qu’un préprocesseur ?

La question se pose légitimement : si SASS et LESS proposent déjà des variables depuis des années, quel est l’intérêt des variables CSS natives ? La réponse tient en plusieurs avantages fondamentaux :

  • Dynamisme en temps réel : les variables CSS existent dans le DOM et peuvent être modifiées à la volée avec JavaScript. Les variables SASS sont compilées et figées dans le CSS final.
  • Héritage en cascade : les custom properties respectent la cascade CSS. Une variable définie sur un élément parent est accessible par tous ses enfants, et peut être redéfinie localement.
  • Aucune compilation nécessaire : pas besoin d’installer Node.js, Ruby ou un quelconque outil de build. Les variables CSS fonctionnent directement dans le navigateur.
  • Interopérabilité : elles s’intègrent nativement avec les media queries, les pseudo-classes et même les animations CSS.
  • Inspection facile : les DevTools de Chrome et Firefox permettent de visualiser et modifier les variables CSS en direct.

Le saviez-vous ? Selon le W3C, les CSS Custom Properties sont une recommandation officielle (CSS Custom Properties for Cascading Variables Module Level 1), garantissant leur pérennité et leur adoption par tous les moteurs de rendu modernes.

Cela dit, les préprocesseurs gardent des avantages comme les mixins, les boucles et les fonctions complexes. L’idéal est souvent de combiner les deux : SASS pour la logique de compilation, et les variables CSS pour tout ce qui doit être dynamique côté client.

Syntaxe et déclaration des variables CSS

Déclarer une variable CSS

La déclaration d’une variable CSS suit une syntaxe simple mais stricte :

sélecteur {
  --nom-de-la-variable: valeur;
}

Quelques règles essentielles à retenir :

  • Le nom commence obligatoirement par deux tirets (--).
  • Les noms sont sensibles à la casse : --Couleur et --couleur sont deux variables différentes.
  • La valeur peut être n’importe quelle valeur CSS valide : couleur, taille, police, gradient, etc.
  • Une variable peut contenir des valeurs partielles, comme un simple chiffre utilisé dans un calc().

Le sélecteur :root et la portée globale

La convention la plus répandue consiste à déclarer les variables globales dans le pseudo-sélecteur :root, qui cible l’élément racine du document (généralement <html>) :

:root {
  --color-primary: #2c3e50;
  --color-secondary: #e74c3c;
  --color-background: #ecf0f1;
  --font-size-base: 16px;
  --border-radius: 8px;
  --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.1);
}

Ces variables sont ensuite accessibles dans n’importe quel sélecteur du document, puisque :root est l’ancêtre de tous les éléments.

Utiliser une variable avec var()

Pour appeler une variable, on utilise la fonction var() :

.card {
  background-color: var(--color-background);
  border-radius: var(--border-radius);
  box-shadow: var(--shadow-card);
  padding: calc(var(--font-size-base) * 1.5);
}

Notez l’utilisation de calc() combiné avec une variable : c’est un pattern extrêmement puissant pour créer des systèmes de design cohérents basés sur un espacement de base.

Héritage et portée locale des variables CSS

L’un des aspects les plus puissants des variables CSS est leur respect de la cascade et de l’héritage. Une variable définie sur un élément est accessible par tous ses descendants, et elle peut être redéfinie localement sans affecter le reste du document.

:root {
  --color-text: #333;
}

.section-dark {
  --color-text: #fff;
}

p {
  color: var(--color-text);
}

Dans cet exemple, tous les paragraphes seront en gris foncé (#333), sauf ceux situés à l’intérieur d’un élément portant la classe .section-dark, où le texte deviendra blanc. Cette mécanique est fondamentale pour la création de thèmes et de composants réutilisables.

Cette approche permet de créer des composants véritablement encapsulés. Un composant « bouton » peut définir ses propres variables CSS internes, que le contexte parent peut surcharger sans toucher au CSS du composant :

.btn {
  --btn-bg: #3498db;
  --btn-color: #fff;
  --btn-padding: 10px 20px;
  
  background-color: var(--btn-bg);
  color: var(--btn-color);
  padding: var(--btn-padding);
  border: none;
  border-radius: var(--border-radius);
  cursor: pointer;
}

.btn-danger {
  --btn-bg: #e74c3c;
}

.btn-large {
  --btn-padding: 16px 32px;
}

Valeurs de fallback : la sécurité avant tout

La fonction var() accepte un deuxième argument optionnel qui sert de valeur de secours (fallback) au cas où la variable ne serait pas définie :

.element {
  color: var(--color-accent, #e67e22);
  font-size: var(--size-text, 16px);
}

Si --color-accent n’est pas définie dans le contexte courant ou ses ancêtres, la couleur #e67e22 sera utilisée. Ce mécanisme est crucial pour :

  • Garantir un rendu correct même en cas d’oubli de déclaration.
  • Permettre l’utilisation de composants dans des contextes variés.
  • Assurer une dégradation gracieuse pour les navigateurs anciens (bien que leur support soit désormais quasi universel).

Vous pouvez même enchaîner les fallbacks en imbriquant les fonctions var() :

color: var(--color-theme, var(--color-primary, #333));

Créer un thème sombre avec les variables CSS

L’un des cas d’utilisation les plus populaires des variables CSS est la mise en place d’un dark mode (thème sombre). Grâce à l’héritage et à la portée locale, c’est remarquablement simple à implémenter.

Méthode avec une classe sur le body

:root {
  --bg-color: #ffffff;
  --text-color: #2c3e50;
  --card-bg: #f8f9fa;
  --border-color: #dee2e6;
}

[data-theme="dark"] {
  --bg-color: #1a1a2e;
  --text-color: #e0e0e0;
  --card-bg: #16213e;
  --border-color: #0f3460;
}

body {
  background-color: var(--bg-color);
  color: var(--text-color);
  transition: background-color 0.3s ease, color 0.3s ease;
}

Il suffit ensuite d’un simple script JavaScript pour basculer le thème :

document.getElementById('toggle-theme').addEventListener('click', () => {
  const html = document.documentElement;
  const current = html.getAttribute('data-theme');
  html.setAttribute('data-theme', current === 'dark' ? 'light' : 'dark');
});

Méthode avec prefers-color-scheme

Pour respecter automatiquement les préférences système de l’utilisateur, vous pouvez utiliser la media query prefers-color-scheme :

@media (prefers-color-scheme: dark) {
  :root {
    --bg-color: #1a1a2e;
    --text-color: #e0e0e0;
    --card-bg: #16213e;
  }
}

Cette approche est idéale pour offrir une expérience native et respectueuse des choix de l’utilisateur, tout en gardant la possibilité d’un toggle manuel. Si vous travaillez sur des projets React, vous pouvez combiner cette technique avec les bonnes pratiques du SEO ReactJS pour garantir performance et accessibilité.

Variables CSS et JavaScript : le duo gagnant

C’est ici que les variables CSS se démarquent radicalement des variables de préprocesseurs. Puisqu’elles vivent dans le DOM, JavaScript peut les lire et les modifier en temps réel.

Lire une variable CSS

const root = getComputedStyle(document.documentElement);
const primaryColor = root.getPropertyValue('--color-primary').trim();
console.log(primaryColor); // #2c3e50

Modifier une variable CSS

document.documentElement.style.setProperty('--color-primary', '#9b59b6');

Cette ligne unique change instantanément la couleur principale sur l’ensemble du site. Imaginez les possibilités :

  • Personnalisation utilisateur : laisser l’utilisateur choisir la couleur d’accent de l’interface.
  • Animations interactives : modifier des variables en fonction de la position de la souris ou du scroll.
  • Thèmes dynamiques : charger des palettes de couleurs depuis une API et les appliquer sans recharger la page.
  • Responsive dynamique : ajuster des tailles et espacements selon des calculs JavaScript complexes.

Exemple concret : slider de couleur interactif

Voici un cas pratique souvent utilisé dans les interfaces de personnalisation :

<input type="range" id="hue-slider" min="0" max="360" value="200">

<script>
document.getElementById('hue-slider').addEventListener('input', (e) => {
  document.documentElement.style.setProperty(
    '--color-primary',
    `hsl(${e.target.value}, 70%, 50%)`
  );
});
</script>

En déplaçant le curseur, la couleur principale change en temps réel sur toute la page. Ce type d’interaction est impossible avec des variables SASS compilées.

Bonnes pratiques pour structurer vos variables CSS

Un projet bien organisé repose sur une nomenclature claire et une structure logique de ses variables. Voici les conventions recommandées par la communauté front-end :

Convention de nommage

Adoptez une nomenclature cohérente et descriptive :

  • Par catégorie : --color-*, --font-*, --spacing-*, --shadow-*, --border-*
  • Par composant : --btn-*, --card-*, --nav-*, --modal-*
  • Par intention : --color-success, --color-danger, --color-warning

Évitez les noms trop spécifiques comme --blue-500 qui perdent leur sens si vous changez de palette. Préférez --color-primary ou --color-accent.

Organisation en couches

Une approche éprouvée consiste à séparer les variables en deux niveaux :

/* Couche 1 : tokens de design (valeurs brutes) */
:root {
  --blue-500: #3498db;
  --blue-700: #2980b9;
  --gray-100: #f8f9fa;
  --gray-900: #212529;
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 32px;
}

/* Couche 2 : variables sémantiques (intentions) */
:root {
  --color-primary: var(--blue-500);
  --color-primary-hover: var(--blue-700);
  --color-background: var(--gray-100);
  --color-text: var(--gray-900);
  --spacing-section: var(--space-lg);
}

Ainsi, changer toute la palette de couleurs ne nécessite que de modifier les variables sémantiques. Ce pattern est utilisé par les design systems les plus robustes.

Variables CSS et media queries responsive

Les variables CSS se combinent parfaitement avec les media queries pour adapter le design à différentes tailles d’écran :

:root {
  --font-size-h1: 2.5rem;
  --container-padding: 40px;
  --grid-columns: 3;
}

@media (max-width: 768px) {
  :root {
    --font-size-h1: 1.8rem;
    --container-padding: 16px;
    --grid-columns: 1;
  }
}

h1 {
  font-size: var(--font-size-h1);
}

.container {
  padding: var(--container-padding);
}

.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
}

Au lieu de réécrire des règles CSS entières dans chaque media query, vous ne modifiez que les valeurs des variables. Le résultat : un code plus concis, plus lisible et infiniment plus maintenable. Ce type d’optimisation est essentiel pour les développeurs qui souhaitent aussi créer des thèmes WordPress performants et adaptatifs.

Cas pratiques avancés avec les variables CSS

Système d’espacement cohérent

Créez un système d’espacement basé sur un multiplicateur :

:root {
  --space-unit: 8px;
  --space-xs: calc(var(--space-unit) * 0.5);   /* 4px */
  --space-sm: var(--space-unit);                /* 8px */
  --space-md: calc(var(--space-unit) * 2);      /* 16px */
  --space-lg: calc(var(--space-unit) * 3);      /* 24px */
  --space-xl: calc(var(--space-unit) * 4);      /* 32px */
  --space-xxl: calc(var(--space-unit) * 6);     /* 48px */
}

Palette de couleurs avec transparence

Stockez les composantes de couleur séparément pour générer des variantes avec transparence :

:root {
  --color-primary-rgb: 52, 152, 219;
}

.overlay {
  background-color: rgba(var(--color-primary-rgb), 0.2);
}

.badge {
  background-color: rgba(var(--color-primary-rgb), 0.1);
  color: rgb(var(--color-primary-rgb));
}

Animations dynamiques

Les variables CSS peuvent piloter des animations avec des valeurs modifiables :

:root {
  --animation-duration: 0.3s;
  --animation-easing: cubic-bezier(0.4, 0, 0.2, 1);
}

.btn {
  transition: all var(--animation-duration) var(--animation-easing);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --animation-duration: 0.01s;
  }
}

Notez comment la media query prefers-reduced-motion permet de respecter les préférences d’accessibilité en réduisant simplement la durée de la variable.

Erreurs courantes à éviter avec les variables CSS

Même si les variables CSS sont relativement simples, certaines erreurs reviennent fréquemment chez les développeurs :

  • Oublier les deux tirets : écrire -ma-variable au lieu de --ma-variable ne créera pas de variable CSS. Le double tiret est obligatoire.
  • Utiliser var() dans un nom de propriété : var(--prop): value; ne fonctionne pas. Les variables ne peuvent remplacer que des valeurs, pas des noms de propriétés.
  • Confondre unité et valeur : --size: 16; suivi de font-size: var(--size)px; ne fonctionnera pas. Utilisez plutôt --size: 16px; ou font-size: calc(var(--size) * 1px);.
  • Créer des références circulaires : --a: var(--b); --b: var(--a); provoquera une valeur invalide.
  • Surcharger sans portée : modifier une variable globale dans un composant sans utiliser un sélecteur local peut provoquer des effets de bord inattendus.

« CSS custom properties are not just variables — they are a cascade-aware, inheritance-respecting mechanism that brings a new level of power to CSS. »

— Lea Verou, CSS Secrets (O’Reilly Media)

Compatibilité navigateur et alternatives

La compatibilité des variables CSS est aujourd’hui excellente. Tous les navigateurs modernes les supportent pleinement :

  • Chrome : depuis la version 49
  • Firefox : depuis la version 31
  • Safari : depuis la version 9.1
  • Edge : depuis la version 15
  • Opera : depuis la version 36

Le seul absent notable reste Internet Explorer, qui ne supporte pas du tout les custom properties. Si votre projet doit encore gérer IE (ce qui devient de plus en plus rare), vous pouvez :

  • Fournir des valeurs de fallback classiques avant la règle utilisant var().
  • Utiliser le polyfill css-vars-ponyfill pour émuler le comportement.
  • Combiner avec un préprocesseur qui génère les valeurs statiques en complément.
/* Fallback pour IE */
.element {
  color: #3498db;                    /* IE et anciens navigateurs */
  color: var(--color-primary, #3498db); /* Navigateurs modernes */
}

Questions fréquentes

Quelle est la différence entre les variables CSS et les variables SASS ?

Les variables CSS (custom properties) sont natives du navigateur et peuvent être modifiées dynamiquement avec JavaScript ou via le DOM. Les variables SASS sont compilées et remplacées par leurs valeurs statiques lors de la génération du CSS. Les variables CSS supportent l’héritage en cascade, tandis que les variables SASS n’existent que lors de la compilation.

Les variables CSS sont-elles supportées par tous les navigateurs ?

Les variables CSS sont supportées par tous les navigateurs modernes : Chrome, Firefox, Safari, Edge et Opera. Seul Internet Explorer ne les prend pas en charge. Pour les projets nécessitant une compatibilité IE, il faut prévoir des valeurs de fallback ou utiliser un polyfill.

Peut-on modifier une variable CSS avec JavaScript ?

Oui, c’est l’un des grands avantages des variables CSS. Vous pouvez les modifier via JavaScript avec la méthode element.style.setProperty(‘–ma-variable’, ‘nouvelleValeur’). Cela permet de créer des thèmes dynamiques, des animations interactives ou de modifier l’apparence d’un site en temps réel sans recharger la page.

Conclusion : passez aux variables CSS dès maintenant

Les variables CSS ne sont pas un simple gadget syntaxique : elles transforment en profondeur la manière dont on structure, maintient et fait évoluer les feuilles de style. En adoptant les custom properties, vous gagnez en maintenabilité (une seule source de vérité pour chaque valeur), en flexibilité (thèmes dynamiques, responsive simplifié) et en productivité (moins de duplication, moins d’erreurs).

Que vous construisiez un petit site vitrine ou un design system complet, les variables CSS devraient être l’un des premiers outils que vous mettez en place. Commencez par extraire vos couleurs et espacements récurrents dans :root, puis étendez progressivement votre système de tokens.

Pour aller plus loin, n’hésitez pas à expérimenter avec la manipulation JavaScript des variables, la création de thèmes utilisateur personnalisables et les techniques avancées comme les palettes HSL dynamiques. Le CSS moderne est plus puissant que jamais, et les custom properties en sont l’une des pierres angulaires. Alors, prêt à refactorer vos feuilles de style ?