Introduction aux variables CSS
Les variables CSS, officiellement appelées custom properties, permettent de stocker des valeurs réutilisables dans vos feuilles de style. Elles transforment votre CSS d'un code statique et répétitif en un système dynamique, maintenable et facilement personnalisable.
Contrairement aux variables des préprocesseurs (Sass, Less), les variables CSS sont natives, fonctionnent dans le navigateur sans compilation, et participent à la cascade CSS. C'est un outil puissant que chaque développeur front-end devrait maîtriser.
Syntaxe des variables CSS
Déclarer une variable
/* Les variables sont préfixées par -- */
:root {
--color-primary: #3498db;
--color-secondary: #2ecc71;
--color-text: #333333;
--color-bg: #ffffff;
--font-main: 'Inter', sans-serif;
--font-size-base: 16px;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 2rem;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 16px;
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
--transition-fast: 0.15s ease;
--transition-normal: 0.3s ease;
}
Utiliser une variable
/* La fonction var() lit la valeur de la variable */
.button {
background-color: var(--color-primary);
color: var(--color-bg);
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius-md);
font-family: var(--font-main);
box-shadow: var(--shadow-sm);
transition: all var(--transition-fast);
}
/* Valeur de repli (fallback) */
.card {
padding: var(--spacing-card, 1.5rem);
/* Si --spacing-card n'existe pas, utilise 1.5rem */
}
/* Fallback en cascade */
.text {
color: var(--color-accent, var(--color-primary, blue));
}
Portée et cascade des variables CSS
Variables globales vs locales
/* Variables globales (accessibles partout) */
:root {
--color-primary: #3498db;
--color-bg: #ffffff;
}
/* Variables locales (limitées à un sélecteur) */
.dark-section {
--color-bg: #1a1a2e;
--color-text: #e0e0e0;
}
/* Les enfants de .dark-section hériteront des nouvelles valeurs */
.dark-section .card {
background: var(--color-bg); /* #1a1a2e, pas #ffffff */
color: var(--color-text); /* #e0e0e0 */
}
/* Variables de composant */
.btn {
--btn-bg: var(--color-primary);
--btn-color: white;
--btn-padding: 0.75rem 1.5rem;
--btn-radius: var(--radius-md);
background: var(--btn-bg);
color: var(--btn-color);
padding: var(--btn-padding);
border-radius: var(--btn-radius);
}
/* Variantes par simple redéfinition */
.btn-danger {
--btn-bg: #e74c3c;
}
.btn-success {
--btn-bg: #27ae60;
}
.btn-outline {
--btn-bg: transparent;
--btn-color: var(--color-primary);
}
Dark mode avec les variables CSS
/* Thème clair (défaut) */
:root {
--color-bg: #ffffff;
--color-bg-secondary: #f8f9fa;
--color-text: #1a1a2e;
--color-text-muted: #6c757d;
--color-border: #dee2e6;
--color-primary: #3498db;
--color-primary-hover: #2980b9;
--shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
/* Thème sombre (media query automatique) */
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #0f0f23;
--color-bg-secondary: #1a1a2e;
--color-text: #e8e8e8;
--color-text-muted: #9ca3af;
--color-border: #2d2d44;
--color-primary: #60a5fa;
--color-primary-hover: #93c5fd;
--shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
}
}
/* Ou avec un toggle classe (JavaScript) */
[data-theme="dark"] {
--color-bg: #0f0f23;
--color-bg-secondary: #1a1a2e;
--color-text: #e8e8e8;
--color-text-muted: #9ca3af;
--color-border: #2d2d44;
--color-primary: #60a5fa;
--shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
}
/* Les composants s'adaptent automatiquement */
body {
background-color: var(--color-bg);
color: var(--color-text);
}
.card {
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
box-shadow: var(--shadow);
}
a { color: var(--color-primary); }
a:hover { color: var(--color-primary-hover); }
Toggle dark mode en JavaScript
// JavaScript pour le toggle
const toggle = document.querySelector('.theme-toggle');
const html = document.documentElement;
// Charger la préférence sauvegardée
const saved = localStorage.getItem('theme');
if (saved) html.setAttribute('data-theme', saved);
toggle.addEventListener('click', () => {
const current = html.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
html.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
});
Design System avec les variables CSS
/* === DESIGN SYSTEM TOURAK DIGITAL === */
:root {
/* Couleurs */
--color-primary-50: #eff6ff;
--color-primary-100: #dbeafe;
--color-primary-200: #bfdbfe;
--color-primary-300: #93c5fd;
--color-primary-400: #60a5fa;
--color-primary-500: #3b82f6;
--color-primary-600: #2563eb;
--color-primary-700: #1d4ed8;
--color-primary-800: #1e40af;
--color-primary-900: #1e3a8a;
/* Typographie */
--font-sans: 'Inter', system-ui, sans-serif;
--font-mono: 'Fira Code', monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
--text-4xl: 2.25rem;
/* Espacement */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
--space-12: 3rem;
--space-16: 4rem;
/* Breakpoints (en tant que référence) */
--bp-sm: 576px;
--bp-md: 768px;
--bp-lg: 992px;
--bp-xl: 1200px;
/* Z-index scale */
--z-dropdown: 100;
--z-sticky: 200;
--z-modal-backdrop: 300;
--z-modal: 400;
--z-tooltip: 500;
--z-toast: 600;
}
Techniques avancées
Variables CSS et calc()
:root {
--base-size: 16px;
--scale: 1.25;
}
h1 { font-size: calc(var(--base-size) * var(--scale) * var(--scale) * var(--scale)); }
h2 { font-size: calc(var(--base-size) * var(--scale) * var(--scale)); }
h3 { font-size: calc(var(--base-size) * var(--scale)); }
p { font-size: var(--base-size); }
/* Espacement dynamique */
.container {
--container-padding: clamp(1rem, 5vw, 3rem);
padding-inline: var(--container-padding);
}
Variables CSS modifiées par JavaScript
// Modifier une variable CSS depuis JS
document.documentElement.style.setProperty('--color-primary', '#e74c3c');
// Lire une variable CSS
const primary = getComputedStyle(document.documentElement)
.getPropertyValue('--color-primary').trim();
// Exemple : couleur dynamique basée sur le scroll
window.addEventListener('scroll', () => {
const hue = (window.scrollY / 5) % 360;
document.documentElement.style.setProperty('--dynamic-hue', hue);
});
Variables CSS vs variables Sass
| Critère | Variables CSS | Variables Sass ($) |
|---|---|---|
| Compilation | Natives, pas de build | Compilées en valeurs statiques |
| Cascade | Participent à la cascade | Pas de cascade |
| Modification JS | Oui, dynamiques | Non, statiques |
| Media queries | Redéfinissables dans @media | Pas dynamiques |
| Dark mode | Simple redéfinition | Nécessite des mixins |
| Performance | Calcul au runtime | Valeurs figées au build |
| Recommandation | Préférez pour les thèmes et les valeurs dynamiques | Préférez pour les calculs complexes au build |
Bonnes pratiques
- Nommez vos variables sémantiquement :
--color-primaryplutôt que--blue. - Utilisez :root pour les variables globales et des sélecteurs spécifiques pour les variables locales.
- Créez une échelle de valeurs pour les couleurs (50 à 900) et les espacements.
- Prévoyez le dark mode dès le départ en utilisant des variables pour toutes les couleurs.
- Documentez vos variables dans un fichier dédié (variables.css ou tokens.css).
- Utilisez des fallbacks pour la compatibilité :
color: var(--primary, #3498db);
Conclusion
Les variables CSS sont un pilier du développement front-end moderne. Elles rendent votre code plus maintenable, facilitent la création de thèmes et de design systems, et permettent des personnalisations dynamiques impossibles avec les préprocesseurs seuls.
Chez Tourak Digital, nous construisons des design systems robustes basés sur les variables CSS. Contactez-nous pour un projet web maintenable et évolutif.