Retour au cours

frontend / css

Fonctions de couleur avancées : relative color, lab/lch, gamut

Leçon 241 exercice

Explication

Ce que vous allez apprendre

  • Comprendre pourquoi oklch est "perceptuellement uniforme" contrairement à hsl
  • Dériver une couleur à partir d'une autre directement en CSS avec la relative color syntax
  • Générer une palette de nuances (100 à 700) à partir d'une seule teinte de base
  • Utiliser des espaces colorimétriques étendus (lab, display-p3) pour des écrans compatibles
  • Comprendre ce que fait le navigateur quand une couleur dépasse le gamut de l'écran

Dans quel contexte ?

Une équipe design doit générer automatiquement les variantes :hover et :disabled de chaque couleur de sa charte, ainsi qu'une palette de 5 nuances (très clair à très foncé) pour chaque couleur de marque, sans dupliquer manuellement des dizaines de valeurs hexadécimales. La relative color syntax et color-mix() en espace oklch permettent de calculer toutes ces variantes directement en CSS, à partir d'une seule variable source.

Étape 1 : rappel, pourquoi oklch bat hsl

Une leçon précédente a introduit oklch et color-mix. Le problème de hsl est que ses variations numériques ne correspondent pas à des variations visuelles régulières : +10 de luminosité paraît énorme sur un jaune, presque invisible sur un bleu.

Étape 2 : ce que "perceptuellement uniforme" signifie

oklch est dit "perceptuellement uniforme" : une même variation numérique produit toujours un changement visuel comparable, quelle que soit la teinte de départ.

Étape 3 : le problème avant la couleur relative

Avant cette fonctionnalité, créer une variante plus sombre d'une couleur pour un :hover demandait de calculer manuellement une nouvelle valeur, ou de dupliquer une variable CSS.

Étape 4 : la solution, dériver directement en CSS

oklch(from var(--primaire) calc(l - 0.1) c h) fait cela directement : elle "ouvre" la couleur source en ses composantes, permet de modifier une seule d'entre elles, et reconstruit la couleur.

Bonne pratique

Utilisez color-mix(in oklch, var(--primaire) 20%, white) pour générer une nuance claire d'une couleur de marque, plutôt que de choisir "à l'œil" une nouvelle valeur hexadécimale. Le résultat reste cohérent et prévisible pour toutes les couleurs de la charte.

Étape 5 : le gamut, une limite physique de l'écran

Passons à un autre sujet : un écran ne peut physiquement afficher qu'un sous-ensemble limité de couleurs, son "gamut". Des espaces comme lab ou display-p3 décrivent des couleurs plus saturées que l'ancien sRGB.

Espace colorimétriqueParticularité
srgbgamut standard, compatible partout
oklch / oklabperceptuellement uniforme, gamut large
lab / lchgamut large, basé sur la perception humaine (CIE)
display-p3gamut étendu, nécessite un écran compatible

Étape 6 : que se passe-t-il hors gamut

Quand une couleur demandée dépasse ce que l'écran peut afficher, le navigateur la remappe automatiquement vers la couleur affichable la plus proche — un mécanisme transparent mais utile à connaître.

Et ensuite ?

Cette leçon prolonge directement la logique de color-mix : mélanger des couleurs dans un espace perceptuel donne des résultats plus prévisibles. La dernière leçon du cours aborde maintenant les styles d'impression avancés.

Commandes & code

Fonctions de couleur avancées

Calculer des couleurs à partir d'autres couleurs, directement en CSS, avec des espaces colorimétriques plus larges que sRGB.

css
/* Rappel rapide : oklch et color-mix (déjà vus) restent la base pratique du quotidien */
:root {
    --primaire: oklch(60% 0.15 250);
}

/* Relative color syntax : dériver une couleur à partir d'une autre, en CSS pur */
.bouton {
    background: var(--primaire);
}
.bouton:hover {
    /* part de --primaire, mais réduit la luminosité (l) de 10 points */
    background: oklch(from var(--primaire) calc(l - 0.1) c h);
}
.bouton:disabled {
    /* réduit juste la saturation (chroma), garde teinte et luminosité */
    background: oklch(from var(--primaire) l calc(c * 0.3) h);
}

/* Fonctionne aussi depuis n'importe quel format source */
.variante-rgb {
    background: rgb(from #2563eb r g calc(b * 0.8));
}
css
/* Espaces colorimétriques étendus : lab/lch (CIE) et oklab/oklch (perceptuel, plus récent) */
.couleurs-larges {
    color: lab(52% 40 59);        /* espace CIE Lab -- gamut plus large que sRGB */
    color: lch(52% 72 35);        /* Lab en coordonnées polaires (teinte explicite) */
    color: oklab(60% 0.1 0.05);   /* équivalent perceptuellement uniforme, plus prévisible */
    color: oklch(60% 0.15 250);   /* le plus pratique au quotidien : L, chroma, teinte séparés */
    color: color(display-p3 1 0.5 0); /* accès direct à un espace élargi (écrans compatibles) */
}
css
/* color-mix() en détail : interpolation dans un espace colorimétrique choisi */
.mix-1 {
    background: color-mix(in oklch, var(--primaire) 70%, white);
    /* mélange perceptuellement plus régulier qu'un mix en sRGB classique */
}
.mix-2 {
    background: color-mix(in srgb, red 50%, blue);
}
.mix-3 {
    /* mélange sans préciser les deux pourcentages : le complément est déduit */
    background: color-mix(in oklch, var(--primaire) 30%, transparent);
}

/* Palette générée à partir d'une seule teinte de base */
:root {
    --primaire-100: color-mix(in oklch, var(--primaire) 20%, white);
    --primaire-300: color-mix(in oklch, var(--primaire) 60%, white);
    --primaire-700: color-mix(in oklch, var(--primaire) 80%, black);
}
css
/* Gamut mapping : que se passe-t-il si la couleur demandée n'existe pas sur l'écran ? */
.couleur-hors-gamut {
    /* oklch permet un chroma théoriquement illimité -> le navigateur "mappe"
       automatiquement vers la couleur affichable la plus proche perceptuellement */
    color: oklch(70% 0.4 30); /* chroma très élevé, probablement hors gamut sRGB */
}

@supports (color: color(display-p3 1 1 1)) {
    /* dégrader proprement pour les écrans qui supportent un gamut plus large */
    .accent {
        color: color(display-p3 0.9 0.2 0.2);
    }
}

Résumé

  • La relative color syntax (oklch(from var(--x) ...)) dérive une teinte/variante sans dupliquer une palette entière à la main.
  • oklch/oklab sont perceptuellement uniformes : une même variation numérique produit un changement visuel cohérent, contrairement à hsl.
  • color-mix(in oklch, ...) produit des dégradés/mélanges plus réguliers qu'un mélange en srgb.
  • Un gamut plus large (lab, display-p3) est automatiquement remappé par le navigateur sur les écrans qui ne le supportent pas.

Exercices pratiques

1 disponible
1

Mission : générer une charte de couleurs cohérente sans dupliquer 40 valeurs

Objectif : Utiliser la relative color syntax et color-mix() en oklch pour dériver des variantes de couleur cohérentes, et expliquer la limite du gamut.

Contexte

Sur theme.css, --primaire: oklch(60% 0.15 250); est la seule couleur de marque définie. L'équipe design veut générer automatiquement, à partir de cette seule variable : une variante :hover plus sombre, une variante :disabled désaturée, et une nuance très claire --primaire-100 utilisable comme fond de badge. Actuellement, un développeur a codé ces trois variantes à la main en hexadécimal, et elles doivent être refaites à chaque changement de --primaire.

Résoudre l’exercice →