Niveau 5 — Les Fonctions CSS

Les Fonctions CSS

Maîtriser les fonctions natives du CSS : calculs, variables, couleurs, gradients et plus pour créer des interfaces dynamiques et maintenables.

1. Comprendre les fonctions CSS

En une phrase : Les fonctions CSS sont des instructions qui calculent, combinent ou génèrent des valeurs dynamiquement — elles transforment des valeurs statiques en valeurs calculées par le navigateur à l'affichage.
CATÉGORIES DES FONCTIONS CSS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ┌── MATHÉMATIQUES ──────────────────┐
  │  calc()    — opérations mixtes     │
  │  min()     — valeur minimale      │
  │  max()     — valeur maximale      │
  │  clamp()   — valeur encadrée      │
  │  round()   — arrondi              │
  │  mod()     — modulo               │
  │  rem()     — reste division       │
  │  sin() cos() tan() etc. — trigo   │
  │  pow() sqrt() abs() hypot()       │
  │  log() exp() sign()               │
  └────────────────────────────────────┘

  ┌── VARIABLES ──────────────────────┐
  │  var()     — propriétés custom    │
  └────────────────────────────────────┘

  ┌── COULEURS ───────────────────────┐
  │  rgb()     rgba()                 │
  │  hsl()     hsla()                 │
  │  hwb()                          │
  │  lab()     lch()                  │
  │  oklch()   oklab()               │
  │  color()   color-mix()           │
  │  light-dark()                     │
  └────────────────────────────────────┘

  ┌── GRADIENTS ──────────────────────┐
  │  linear-gradient()                │
  │  radial-gradient()                │
  │  conic-gradient()                 │
  │  repeating-* gradient()           │
  └────────────────────────────────────┘

  ┌── AUTRES ─────────────────────────┐
  │  url()     — ressources externes  │
  │  attr()    — attributs HTML       │
  │  counter() — compteurs            │
  │  toggle()  — alternance           │
  │  symbol()  — symboles             │
  └────────────────────────────────────┘

Inventaire complet des fonctions CSS par catégorie

2. Les fonctions mathématiques

2.1 calc() — Le couteau suisse

calc() permet de mélanger différentes unités dans une même opération mathématique. C'est la seule fonction qui autorise l'addition/soustraction d'unités incompatibles (ex: 100% - 20px).
Opérateur Description Exemple
+Additioncalc(100% + 20px)
-Soustractioncalc(100% - 40px)
*Multiplicationcalc(var(--base) * 2)
/Divisioncalc(100% / 3)

Exemples pratiques de calc()

/* Mélanger % et px — impossible sans calc() */
.sidebar {
  width: calc(100% - 300px);  /* Prend tout sauf 300px pour la sidebar */
}

/* Espacement fluide avec un padding fixe */
.contenu {
  width: calc(100% - 2rem);   /* % pour le responsive, rem pour le padding */
  padding: 0 1rem;
}

/* Grille avec gap */
.grille {
  display: grid;
  grid-template-columns: repeat(3, calc((100% - 2rem) / 3));
  gap: 1rem;
}

/* Centrer un élément avec taille connue */
.centree {
  position: absolute;
  top: calc(50% - 25px);   /* 50% du parent - moitié de la hauteur */
  left: calc(50% - 100px); /* 50% du parent - moitié de la largeur */
  width: 200px;
  height: 50px;
}

/* Avec des variables CSS */
:root {
  --sidebar: 260px;
  --gap: 1.5rem;
}

.layout {
  display: grid;
  grid-template-columns: var(--sidebar) calc(100% - var(--sidebar) - var(--gap));
  gap: var(--gap);
}

2.2 min() — Plafonner une valeur

min() : la valeur la plus petite parmi les options

/* Plafonner la largeur à 800px maximum */
.contenu {
  width: min(100%, 800px);
  /* Si l'écran fait 600px → 600px */
  /* Si l'écran fait 1200px → 800px (plafond) */
}

/* Typographie responsive sans clamp() */
h1 {
  font-size: min(5vw, 3rem);
  /* Petit écran : 5vw | Grand écran : 3rem max */
}

/* Padding responsive */
.card {
  padding: min(5vw, 2rem);
}

2.3 max() — Plancher une valeur

max() : la valeur la plus grande parmi les options

/* Minimum 300px, sinon 100% */
.colonne {
  width: max(300px, 40%);
  /* Écran 800px → max(300, 320) = 320px */
  /* Écran 600px → max(300, 240) = 300px (plancher) */
}

/* Taille de police minimale garantie */
.texte {
  font-size: max(1rem, 2vw);
  /* Ne descend jamais sous 1rem */
}

/* Largeur minimale de conteneur */
.conteneur {
  width: max(90%, 600px);
}

2.4 clamp() — La fonction reine

clamp(min, préféré, max) combine min() et max() en une seule fonction. C'est la solution la plus élégante pour la typographie fluide et les espaces adaptatifs.

clamp() en action

/* Syntaxe : clamp(valeur-min, valeur-préférée, valeur-max) */

/* Titre fluide : de 1.5rem à 4rem */
h1 {
  font-size: clamp(1.5rem, 4vw + 0.5rem, 4rem);
}

/* Texte de corps fluide */
p {
  font-size: clamp(1rem, 1.2vw + 0.5rem, 1.25rem);
}

/* Espacement horizontal responsive */
.section {
  padding: clamp(1rem, 5vw, 4rem) clamp(1rem, 3vw, 2rem);
}

/* Largeur de conteneur */
.conteneur {
  width: min(90%, clamp(600px, 80%, 1200px));
}

/* Hauteur minimale de section */
.hero {
  min-height: clamp(400px, 80vh, 900px);
}
max(300px, 50%)
min(100%, 500px)
clamp(200px, 40%, 400px)

2.5 Imbrication de fonctions

/* Les fonctions mathématiques peuvent se combiner */
.titre {
  /* min(max(minimum, préféré), maximum) */
  font-size: min(max(1.2rem, 3vw), 2.5rem);
}

/* Avec calc() à l'intérieur */
.box {
  width: calc(100% - clamp(2rem, 5vw, 6rem));
}

/* Variables dans calc() */
:root {
  --padding: 1.5rem;
}

.container {
  width: calc(100% - var(--padding) * 2);
}

/* Utiliser calc() pour des calculs complexes */
.grille-3 {
  grid-template-columns:
    repeat(3, calc((100% - 2 * var(--gap)) / 3));
}

2.6 Nouvelles fonctions mathématiques (2023+)

Fonction Description Exemple
round()Arrondir à un pasround(nearest, 45.5, 10) → 50
mod()Modulo (reste positif)mod(15, 6) → 3
rem()Reste de division signéerem(-15, 6) → -3
abs()Valeur absolueabs(-5) → 5
sign()Signe (-1, 0, 1)sign(-5) → -1
sin()Sinussin(45deg) → 0.707
cos()Cosinuscos(0) → 1
pow()Puissancepow(2, 3) → 8
sqrt()Racine carréesqrt(9) → 3
/* Exemple : rotation circulaire avec sin/cos */
.orbite {
  --angle: 90deg;
  --rayon: 100px;
  transform:
    translate(
      calc(cos(var(--angle)) * var(--rayon)),
      calc(sin(var(--angle)) * var(--rayon))
    );
}

/* Exemple : arrondir au pas de 8px le plus proche */
.taille {
  width: round(nearest, 45.5px, 8px);  /* → 48px */
}

3. Les variables CSS — var()

var(--nom) insère la valeur d'une propriété personnalisée (custom property). C'est le fondement du Design System en CSS moderne.

3.1 Syntaxe et fonctionnement

/* Déclaration (n'importe où, souvent :root) */
:root {
  --couleur-primaire: #2563eb;
  --espace-md: 1.5rem;
  --police: 'Segoe UI', system-ui, sans-serif;
}

/* Utilisation */
.bouton {
  background: var(--couleur-primaire);
  padding: var(--espace-md);
  font-family: var(--police);
}

/* Valeur de fallback (défaut) */
.titre {
  color: var(--couleur-titre, #1e293b);
  /* Si --couleur-titre n'est pas défini, utilise #1e293b */
}

/* Fallback avec une deuxième variable */
.texte {
  color: var(--texte-secondaire, var(--texte-primaire, #64748b));
}

/* Valeur de fallback complète (avec unité) */
.bloc {
  font-size: var(--taille-titre, 1.5rem);
  padding: var(--pad-md, 1rem);
}

3.2 Scoping des variables

/* Variables globales (racine) */
:root {
  --couleur: blue;
}

/* Variables locales (un composant) */
.card {
  --couleur: green;      /* Redéfinition locale */
  color: var(--couleur); /* Utilise green dans .card */
}

.card .titre {
  color: var(--couleur); /* Hérite green de .card */
}

/* Les variables sont HÉRITÉES — comme le font-size */
parent {
  --x: 10px;
}

  enfant {
    --x: 20px;     /* Redéfinition locale */
  }

    petit-enfant {
      /* var(--x) → 20px (hérite de enfant, pas parent) */
    }

/* Réinitialisation */
.component {
  --couleur: initial;    /* Remet à la valeur par défaut (transparent) */
  --couleur: revert;     /* Remet à la valeur du user-agent */
  --couleur: unset;      /* Réinitialise (transparent pour les custom props) */
}

3.3 Variables et pseudo-classes

/* Modifier des variables au survol */
.theme {
  --bg: #ffffff;
  --texte: #1e293b;
  background: var(--bg);
  color: var(--texte);
  transition: --bg 0.3s, --texte 0.3s;
}

.theme:hover {
  --bg: #1e293b;
  --texte: #f8fafc;
}

/* Dark mode avec prefers-color-scheme */
:root {
  --bg: #ffffff;
  --texte: #1e293b;
  --card-bg: #f1f5f9;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f172a;
    --texte: #e2e8f0;
    --card-bg: #1e293b;
  }
}

/* Avec data-attributes */
[data-theme="sombre"] {
  --bg: #1a1a2e;
  --texte: #eee;
}
--couleur-primaire: #2563eb
--couleur-succes: #16a34a
--couleur-erreur: #dc2626

3.4 Pièges courants de var()

Erreur : utilisation incorrecte dans calc()
/* ❌ FAUX — la variable doit avoir l'unité OU l'unité doit être à l'extérieur */
.marge {
  margin: calc(var(--espace) * 2);   /* ❌ si --espace: 10, pas d'unité */
  margin: calc(var(--espace) * 2);   /* ✅ si --espace: 10px */
}

/* ✅ BON — unité dans la variable */
:root { --espace: 10px; }
.box  { padding: calc(var(--espace) * 2); } /* 20px */

/* ❌ Les custom properties ne peuvent PAS être des noms de propriétés */
.el {
  var(--prop) : value;  /* ❌ impossible */
}

/* ✅ On ne peut que les UTILISER en valeur */
.el {
  color: var(--couleur);  /* ✅ */
}

4. Les fonctions de couleurs

4.1 Tableau comparatif

Fonction Syntaxe Canal alpha Espace colorimétrique
rgb()rgb(rouge, vert, bleu)rgba(r,g,b,a)sRGB
hsl()hsl(teinte, saturation, luminosité)hsla(h,s,l,a)sRGB
hwb()hwb(teinte, blanc, noir)4e paramètresRGB
lab()lab(l a b)4e paramètreCIE Lab
oklch()oklch(l c h)4e paramètreOKLCH (perceptuellement uniforme)
oklab()oklab(l a b)4e paramètreOKLab

4.2 rgb() / rgba()

/* rgb() — les 3 canaux rouge, vert, bleu (0-255) */
.rouge {
  color: rgb(255, 0, 0);          /* Rouge pur */
  background: rgb(37, 99, 235);   /* Bleu primaire */
}

/* Avec pourcentage */
.teinte {
  background: rgb(50%, 50%, 50%);  /* Gris moyen */
}

/* Avec alpha (transparence) */
.transparent {
  background: rgba(37, 99, 235, 0.2);  /* 20% d'opacité */
}

/* Nouvelle syntaxe avec / pour l'alpha */
.nouveau {
  background: rgb(37 99 235 / 0.3);    /* Syntaxe modernisée */
}

/* Avec espace colorimétrique */
.precis {
  color: color(display-p3 1 0.5 0);  /* Gamut plus large (P3) */
}

4.3 hsl() / hsla()

/* hsl() — teinte (0-360), saturation (0-100%), luminosité (0-100%) */
.primaire {
  color: hsl(217, 91%, 60%);  /* Bleu primaire */
}

/* Avec alpha */
.demi-transparent {
  background: hsl(217, 91%, 60%, 0.3);
}

/* Nouvelle syntaxe */
.modern {
  background: hsl(217 91% 60% / 0.3);
}

/* Créer une palette à partir d'une teinte de base */
:root {
  --teinte: 217;    /* La teinte de base */
  --sat: 91%;       /* La saturation de base */
}

.primaire-50  { background: hsl(var(--teinte), var(--sat), 97%); }
.primaire-100 { background: hsl(var(--teinte), var(--sat), 94%); }
.primaire-200 { background: hsl(var(--teinte), var(--sat), 86%); }
.primaire-500 { background: hsl(var(--teinte), var(--sat), 57%); }
.primaire-700 { background: hsl(var(--teinte), var(--sat), 44%); }
.primaire-900 { background: hsl(var(--teinte), var(--sat), 25%); }

4.4 oklch() — La couleur moderne

oklch() (OK Lightness Chroma Hue) est l'espace colorimétrique le plus récent. Il est perceptuellement uniforme : une même différence de valeur correspond à une même différence perçue, ce qui est idéal pour créer des palettes harmonieuses.
/* oklch(luminosité chroma teinte) */
/* Luminosité : 0 (noir) à 1 (blanc) */
/* Chroma : 0 (gris) à ~0.4 (très saturé) */
/* Teinte : 0 à 360deg */

.bleu {
  color: oklch(0.6 0.2 250);
}

/* Comparaison avec hsl — même luminosité perçue */
.clair  { color: oklch(0.85 0.1 120); }  /* Vert clair */
.moyen  { color: oklch(0.65 0.15 120); } /* Vert moyen */
.fonce  { color: oklch(0.4 0.12 120); }  /* Vert foncé */

/* Alpha */
.transparent {
  background: oklch(0.6 0.2 250 / 0.5);
}

/* Palette harmonieuse : même chroma et teinte, luminosité variable */
:root {
  --primary-100: oklch(0.95 0.05 250);
  --primary-200: oklch(0.89 0.09 250);
  --primary-300: oklch(0.82 0.13 250);
  --primary-400: oklch(0.72 0.17 250);
  --primary-500: oklch(0.62 0.19 250);
  --primary-600: oklch(0.52 0.17 250);
  --primary-700: oklch(0.42 0.14 250);
  --primary-800: oklch(0.33 0.10 250);
  --primary-900: oklch(0.25 0.07 250);
}

4.5 color-mix() — Mélanger des couleurs

/* color-mix(in espace, couleur1, couleur2, proportion) */
.primaire-mixte {
  /* 50% de bleu + 50% de rouge = violet */
  background: color-mix(in oklch, #2563eb 50%, #dc2626 50%);
}

/* Variantes d'une couleur */
.bleu-100 { background: color-mix(in oklch, #2563eb 10%, white); }
.bleu-200 { background: color-mix(in oklch, #2563eb 20%, white); }
.bleu-300 { background: color-mix(in oklch, #2563eb 30%, white); }
.bleu-500 { background: #2563eb; }
.bleu-700 { background: color-mix(in oklch, #2563eb 70%, black); }
.bleu-900 { background: color-mix(in oklch, #2563eb 90%, black); }

/* Mélanger avec transparent pour l'alpha */
.bleu-50pct {
  background: color-mix(in oklch, #2563eb 50%, transparent);
}

/* Mélanger des variables */
.btn-hover {
  background: color-mix(in oklch, var(--primary) 80%, black);
}
50/50
70/30
+white
+black

4.6 light-dark() — Couleur adaptative

/* light-dark(couleur-claire, couleur-sombre) */
/* Nécessite color-scheme: light dark */
:root {
  color-scheme: light dark;
}

body {
  background: light-dark(#ffffff, #0f172a);
  color: light-dark(#1e293b, #e2e8f0);
}

.card {
  background: light-dark(#f1f5f9, #1e293b);
  border: 1px solid light-dark(#e2e8f0, #334155);
}

/* Avantage : pas besoin de media query ! */

5. Les fonctions url() et attr()

5.1 url() — Ressources externes

/* Image de fond */
.bg {
  background-image: url('images/pattern.png');
  background-image: url('https://example.com/photo.webp');
}

/* Police web */
@font-face {
  font-family: 'MaPolice';
  src: url('fonts/mapolice.woff2') format('woff2'),
       url('fonts/mapolice.woff') format('woff');
}

/* Cursor personnalisé */
.custom-cursor {
  cursor: url('cursors/pointer.cur'), pointer;
}

/* Mask (masque SVG) */
.masked {
  mask-image: url('mask.svg');
  mask-image: url('data:image/svg+xml,...'); /* inline data URI */
}

/* Clip-path avec ressource */
.clipped {
  clip-path: url('#mon-clip');  /* Référence à un SVG inline */
}

/* Fetch avec modifiers (futur) */
.avatar {
  image-set(
    url('avatar.avif') type('image/avif'),
    url('avatar.webp') type('image/webp'),
    url('avatar.jpg') type('image/jpeg')
  );
}

5.2 attr() — Valeurs depuis le HTML

/* Utiliser un attribut HTML en CSS */
/* 
*/ [data-tooltip]::after { content: attr(data-tooltip); /* Lit l'attribut data-tooltip */ position: absolute; background: #333; color: #fff; padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.75rem; white-space: nowrap; } /* Nom du lien */ [href]::after { content: ' → ' attr(href); font-size: 0.8em; color: #666; } /* Progress bar avec data-attributes */ /*
*/ .progress::after { content: ''; width: attr(data-value %, 0); /* ⚠️ Actuellement limité */ /* La plupart des navigateurs ne supportent attr() que pour content */ } /* ⚠️ Limitation actuelle de attr() */ /* En 2024-2025, attr() ne fonctionne que pour la propriété content. La proposition étendue (attr() pour toutes propriétés) est en cours. Vérifie compatibilité avant usage. */

6. Les fonctions de gradients

6.1 linear-gradient()

/* Basique : de haut en bas */
.gradient-1 {
  background: linear-gradient(#2563eb, #7c3aed);
}

/* Direction personnalisée */
.gradient-2 {
  background: linear-gradient(45deg, #2563eb, #7c3aed);
}

/* Avec mot-clé de direction */
.gradient-3 {
  background: linear-gradient(to right, #2563eb, #7c3aed);
  background: linear-gradient(to bottom right, #2563eb, #7c3aed);
}

/* Stops de couleur avec position */
.gradient-4 {
  background: linear-gradient(
    to right,
    #2563eb 0%,
    #7c3aed 50%,
    #dc2626 100%
  );
}

/* Plusieurs couleurs */
.gradient-5 {
  background: linear-gradient(135deg, #ff6b6b, #feca57, #48dbfb, #ff9ff3);
}

/* Répété */
.gradient-6 {
  background: repeating-linear-gradient(
    45deg,
    #2563eb,
    #2563eb 10px,
    #7c3aed 10px,
    #7c3aed 20px
  );
}
linear-gradient(135deg, bleu, violet)
linear-gradient multi-couleurs
repeating-linear-gradient

6.2 radial-gradient()

/* Cercle depuis le centre */
.radial-1 {
  background: radial-gradient(circle, #2563eb, #7c3aed);
}

/* Ellipse (par défaut) */
.radial-2 {
  background: radial-gradient(ellipse, #2563eb, #7c3aed);
}

/* Position personnalisée */
.radial-3 {
  background: radial-gradient(circle at top left, #2563eb, #7c3aed);
}

/* Taille au plus proche du coin */
.radial-4 {
  background: radial-gradient(circle closest-corner, #2563eb, transparent);
}

/* Tailles nommées */
.radial-5 {
  background: radial-gradient(circle farthest-side, #2563eb, #7c3aed);
  /* closest-side, closest-corner, farthest-side, farthest-corner */
}
radial-gradient(circle at 30% 50%)

6.3 conic-gradient()

/* Dégradé conique (cercle) */
.conic-1 {
  background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
}

/* Avec position et taille */
.conic-2 {
  background: conic-gradient(from 45deg at 50% 50%, #2563eb, #7c3aed);
}

/* Camembert / diagramme */
.camembert {
  background: conic-gradient(
    #2563eb 0% 35%,
    #7c3aed 35% 60%,
    #dc2626 60% 80%,
    #16a34a 80% 100%
  );
  border-radius: 50%;
}

/* Rayon de soleil */
.rayon {
  background: repeating-conic-gradient(
    #2563eb 0deg 10deg,
    #7c3aed 10deg 20deg
  );
}
conic-gradient

7. Erreurs fréquentes

Erreur 1 : Espaces manquants dans calc()
/* ❌ FAUX — les opérateurs + et - nécessitent des espaces */
width: calc(100%-20px);    /* Erreur de parsing */
width: calc(100%- 20px);   /* Erreur aussi */

/* ✅ BON — espaces obligatoires autour de + et - */
width: calc(100% - 20px);  /* Correct */

/* Les opérateurs * et / n'exigent pas d'espaces */
width: calc(100% / 3);     /* OK */
width: calc(var(--x) * 2); /* OK */
Erreur 2 : var() sans fallback dans un contexte critique
/* ❌ Si --couleur n'est pas défini, la propriété est ignorée */
.bouton {
  background: var(--couleur);  /* Rien si --couleur inexistant */
}

/* ✅ Toujours prévoir un fallback */
.bouton {
  background: var(--couleur, #2563eb);  /* Fallback si absent */
}

/* ✅ Vérifier si une variable existe */
.bouton {
  background: var(--couleur, var(--theme-primary, #2563eb));
}
Erreur 3 : Confondre les espaces dans les couleurs modernes
/* ❌ Ancienne syntaxe avec virgules (encore supportée) */
.rgb-old { color: rgb(37, 99, 235); }

/* ✅ Nouvelle syntaxe avec espaces (recommandée) */
.rgb-new { color: rgb(37 99 235); }

/* ❌ Mélangé les deux syntaxes */
.rgb-bad { color: rgb(37 99, 235); }  /* Erreur ! */

/* Alpha avec la nouvelle syntaxe */
.rgba { color: rgb(37 99 235 / 0.5); }
.hsla { color: hsl(217 91% 60% / 0.3); }
Erreur 4 : Abus de url() sans vérifier le chemin
/* ❌ Chemin relatif qui casse quand on change la structure */
.bg {
  background: url('../images/photo.jpg');
}

/* ✅ Utiliser des chemins absolus ou des variables */
.bg {
  background: url('/assets/images/photo.jpg');
}

/* ✅ Ou melhor, utiliser des imports CSS/variables */
:root {
  --bg-pattern: url('/assets/pattern.svg');
}
.element {
  background-image: var(--bg-pattern);
}

8. Bonnes pratiques

Règles d'or pour les fonctions CSS :
  • Utiliser clamp() pour toute taille qui doit être fluide (typographie, espacements, largeurs).
  • Définir les variables dans :root pour les tokens globaux, et localement pour les composants.
  • Toujours prévoir un fallback avec var(--x, valeur-defaut).
  • Préférer oklch() pour les palettes de couleurs (perceptuellement uniforme).
  • Utiliser color-mix() au lieu de créer des variantes manuellement.
  • Imbriquer les fonctions avec parcimonie — ne pas créer de calc() à 5 niveaux de profondeur.
  • Documenter les variables avec des commentaires pour les équipes.
Architecture de variables :
  • Token layer : valeurs brutes (couleurs, espaces) dans :root.
  • Semantic layer : aliases contextuels (--bg-primary, --text-secondary).
  • Component layer : variables locales au composant (--card-padding).

9. Mini-défi

Exercice 1 : Typographie fluide

Crée un système de typographie responsive avec clamp() pour 5 niveaux de titres (h1 à h5) :

  • h1 : de 1.75rem à 4rem
  • h2 : de 1.5rem à 3rem
  • h3 : de 1.25rem à 2rem
  • h4 : de 1.1rem à 1.5rem
  • h5 : de 1rem à 1.25rem

Exercice 2 : Palette avec oklch()

Crée une palette de 9 nuances (50 à 900) d'une couleur au choix en utilisant oklch() et des variables CSS. La palette doit être harmonieuse.

Exercice 3 : Layout avec calc()

Crée un layout à 3 colonnes avec calc() : sidebar gauche de 240px, sidebar droite de 200px, contenu principal flexible, avec un gap de 1.5rem.

Exercice 4 : Bouton avec color-mix()

Crée un composant bouton qui génère automatiquement ses états (hover, active) avec color-mix() au lieu de définir des couleurs manuellement.

Exercice 5 : Système complet

Combinaison : crée un mini design system utilisant clamp(), var(), color-mix() et oklch() pour un blog simple avec header, article, sidebar et footer.

10. Projet d'application

Projet : Design System en Variables CSS

Crée un fichier design-system.css complet :

/* design-system.css */
:root {
  /* ─── TOKENS ─── */
  --color-base-hue: 250;

  /* Palette générée avec oklch */
  --primary-50:  oklch(0.97 0.02 var(--color-base-hue));
  --primary-100: oklch(0.93 0.04 var(--color-base-hue));
  --primary-200: oklch(0.87 0.08 var(--color-base-hue));
  --primary-300: oklch(0.78 0.12 var(--color-base-hue));
  --primary-400: oklch(0.68 0.16 var(--color-base-hue));
  --primary-500: oklch(0.58 0.18 var(--color-base-hue));
  --primary-600: oklch(0.48 0.16 var(--color-base-hue));
  --primary-700: oklch(0.39 0.13 var(--color-base-hue));
  --primary-800: oklch(0.31 0.10 var(--color-base-hue));
  --primary-900: oklch(0.23 0.07 var(--color-base-hue));

  /* Semantic tokens */
  --bg-primary:   light-dark(#ffffff, #0f172a);
  --bg-secondary: light-dark(#f8fafc, #1e293b);
  --text-primary: light-dark(#1e293b, #e2e8f0);
  --text-muted:   light-dark(#64748b, #94a3b8);

  /* Spacing scale (base: 4px) */
  --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;

  /* Typography */
  --font-sans: 'Inter', system-ui, sans-serif;
  --font-mono: 'Fira Code', monospace;

  --text-xs:   clamp(0.7rem, 0.65rem + 0.25vw, 0.75rem);
  --text-sm:   clamp(0.8rem, 0.78rem + 0.25vw, 0.875rem);
  --text-base: clamp(0.95rem, 0.9rem + 0.25vw, 1rem);
  --text-lg:   clamp(1.05rem, 1rem + 0.3vw, 1.125rem);
  --text-xl:   clamp(1.15rem, 1.05rem + 0.5vw, 1.25rem);
  --text-2xl:  clamp(1.3rem, 1.1rem + 1vw, 1.5rem);
  --text-3xl:  clamp(1.6rem, 1.2rem + 2vw, 2rem);
  --text-4xl:  clamp(2rem, 1.5rem + 2.5vw, 2.5rem);

  /* Layout */
  --container-max: clamp(600px, 90vw, 1200px);
  --sidebar-width: clamp(200px, 25vw, 280px);

  /* Transitions */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --duration-fast: 150ms;
  --duration-normal: 250ms;
}

/* ─── COMPOSANTS ─── */
.button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-6);
  font-size: var(--text-sm);
  font-weight: 600;
  background: var(--primary-500);
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all var(--duration-fast) var(--ease);
}

.button:hover {
  background: color-mix(in oklch, var(--primary-500) 85%, black);
}

.button:active {
  background: color-mix(in oklch, var(--primary-500) 70%, black);
  transform: scale(0.98);
}

.card {
  padding: var(--space-6);
  background: var(--bg-secondary);
  border-radius: 12px;
  border: 1px solid color-mix(in oklch, var(--text-primary) 10%, transparent);
}

.titre-page {
  font-size: var(--text-4xl);
  font-weight: 800;
  line-height: 1.1;
  color: var(--text-primary);
}

11. Révision

Quiz rapide

  1. Quelle est la différence entre min(), max() et clamp() ?
  2. Pourquoi les espaces sont-ils obligatoires autour de + et - dans calc() ?
  3. Quel est l'avantage de oklch() par rapport à hsl() ?
  4. Que fait color-mix(in oklch, #2563eb, white) ?
  5. Comment déclarer une variable CSS ?
  6. Quelle fonction utiliser pour une typographie fluide ?
  7. attr() peut-il être utilisé pour n'importe quelle propriété CSS ?
  8. Comment créer un gradient diabolique avec conic-gradient() ?
  9. Quelle est la bonne syntaxe pour l'alpha avec rgb() moderne ?
  10. Comment fonctionne le fallback de var() ?
Réponses :
  1. min() prend la plus petite valeur, max() la plus grande, clamp() encadre entre min et max avec une valeur préférée.
  2. Les + et - peuvent aussi être des signes unaires. CSS exige des espaces pour les distinguer des opérateurs.
  3. oklch() est perceptuellement uniforme : une même différence de valeur donne une même différence perçue, idéal pour les palettes.
  4. Il mélange le bleu et le blanc dans l'espace OKLCH, résultant en un bleu clair (~50% de chaque).
  5. --nom: valeur; puis var(--nom) pour l'utiliser.
  6. clamp(min, préféré, max) — combine bornes et valeur idéale.
  7. Non, en 2024 attr() ne fonctionne que pour la propriété content.
  8. conic-gradient(#ff0000 0deg 90deg, #00ff00 90deg 180deg, #0000ff 180deg 270deg, #ffff00 270deg 360deg)
  9. rgb(37 99 235 / 0.5) — espaces entre les canaux, / pour l'alpha.
  10. Si la variable n'existe pas, la valeur de fallback après la virgule est utilisée : var(--x, 10px).

12. Mémo rapide (Cheat Sheet)

┌───────────────────────────────────────────────────────────────────┐
│            CHEAT SHEET — FONCTIONS CSS                            │
├───────────────────────────────────────────────────────────────────┤
│                                                                   │
│  MATH :                                                           │
│  ─────                                                            │
│  calc(a ± b)          opérations mixtes d'unités                 │
│  min(a, b, ...)       plus petite valeur                         │
│  max(a, b, ...)       plus grande valeur                         │
│  clamp(m, v, M)       valeur encadrée = max(m, min(v, M))      │
│  round(step, val)     arrondir au pas                             │
│  sin/cos/tan/etc()    fonctions trigonométriques                 │
│  pow/sqrt/abs/sign()  fonctions mathématiques                    │
│                                                                   │
│  VARIABLES :                                                      │
│  ───────────                                                      │
│  --nom: valeur;        déclaration                                │
│  var(--nom)             utilisation                                │
│  var(--nom, defaut)     avec fallback                             │
│  var(--a, var(--b, x))  fallback imbriqué                         │
│                                                                   │
│  COULEURS :                                                       │
│  ─────────                                                        │
│  rgb(r g b / a)        rouge-vert-bleu                           │
│  hsl(h s% l% / a)      teinte-saturation-luminosité             │
│  oklch(l c h / a)      perceptuellement uniforme                 │
│  color-mix(in esp, c1 %, c2 %)  mélange                          │
│  light-dark(clair, sombre)  adaptatif                             │
│                                                                   │
│  GRADIENTS :                                                      │
│  ──────────                                                       │
│  linear-gradient(dir, stops)     dégradé linéaire                │
│  radial-gradient(shape, stops)   dégradé radial                   │
│  conic-gradient(from, stops)     dégradé conique                  │
│  repeating-*-gradient()          dégradé répété                   │
│                                                                   │
│  AUTRES :                                                         │
│  ───────                                                          │
│  url(chemin)            ressource externe                         │
│  attr(nom-attrib)       valeur attribut HTML (content seulement) │
│  counter(nom)           compteur CSS                              │
│                                                                   │
│  ASTUCES :                                                        │
│  ────────                                                         │
│  • calc() : espaces obligatoires autour de + et -                │
│  • var() : toujours prévoir un fallback                           │
│  • clamp() : la fonction pour toute taille fluide                │
│  • oklch() : le meilleur pour les palettes                       │
│  • color-mix() : générer des variantes automatiquement           │
└───────────────────────────────────────────────────────────────────┘

Résumé de toutes les fonctions CSS essentielles