Tutoriels

Interpolation de couleur en CSS : pourquoi OKLCH l'emporte

9 min de lecture

Chaque fois que CSS mélange deux couleurs — dans un dégradé, dans color-mix() ou dans une transition — il effectue une interpolation de couleur : le calcul de valeurs intermédiaires entre une couleur de départ et une couleur d'arrivée. Pendant la majeure partie de l'histoire du web, ce calcul s'est déroulé dans l'espace de couleur sRGB, et les résultats étaient souvent ternes, désaturés ou perceptuellement inégaux. Avec le CSS moderne, vous pouvez désormais choisir l'espace de couleur pour l'interpolation. Ce choix est d'une importance capitale, et OKLCH produit systématiquement les meilleurs résultats.

Ce tutoriel explique pourquoi l'interpolation RGB échoue, où HSL est insuffisant, et pourquoi OKLCH est le bon choix par défaut pour les dégradés et le mélange de couleurs en 2024 et au-delà.

Le problème de l'interpolation RGB : des points médians ternes

Lorsque vous écrivez un dégradé CSS sans spécifier d'espace de couleur, le navigateur interpole en sRGB — il calcule les couleurs intermédiaires en mélangeant linéairement les valeurs des canaux R, G et B de façon indépendante.

Cela semble raisonnable, mais cela s'effondre terriblement lorsque les deux extrémités passent par le milieu du cube sRGB. Considérez un dégradé du rouge au vert :

/* Par défaut : interpole en sRGB */
background: linear-gradient(to right, #FF0000, #00FF00);

Le point médian de ce dégradé en sRGB est #808000 — un olive terne. Mathématiquement, RGB 128, 128, 0 est exactement à mi-chemin entre le rouge et le vert en valeurs de canaux. Mais perceptuellement, cela ne ressemble en rien à un point médian vibrant entre deux primaires vives. Le dégradé s'enfonce dans une vallée boueuse et sombre avant de s'éclaircir de l'autre côté.

Le problème fondamental est que sRGB n'est pas perceptuellement uniforme. Des pas numériques égaux en R, G et B ne correspondent pas à des pas égaux en couleur ou luminosité perçues. Le cube sRGB a été conçu pour le matériel d'affichage, pas pour la vision humaine.

/* Vous pouvez forcer sRGB explicitement */
background: linear-gradient(in srgb, red, blue);

/* Ou utiliser la syntaxe héritée (même résultat) */
background: linear-gradient(red, blue);

Les deux produisent les mêmes points médians désaturés. Le problème vient de l'espace de couleur lui-même, pas de la syntaxe.

Le problème gamma

Il y a une autre subtilité : les valeurs sRGB sont encodées en gamma. Les valeurs sRGB brutes de 0,5 ne correspondent pas à 50% de la lumière physique émise par un écran. Le vrai point médian perceptuel d'un dégradé doit être calculé en lumière linéaire, pas en sRGB encodé en gamma. Le niveau 4 de CSS a introduit in srgb-linear pour répondre à ce problème :

background: linear-gradient(in srgb-linear, red, blue);

Le sRGB linéaire est meilleur que le sRGB en gamma pour les transitions de luminance, mais il ne résout toujours pas les problèmes de dérive de teinte et de chute de saturation, car il reste un espace RGB rectangulaire.

Décalages de teinte HSL

HSL a été introduit comme alternative plus lisible par l'humain à RGB. Sa représentation cylindrique — Teinte sur un angle de 0 à 360, Saturation et Luminosité en pourcentages — facilite le raisonnement sur les relations de couleur. Mais l'interpolation HSL a son propre mode de défaillance caractéristique : les décalages de teinte.

Lorsque vous interpolez entre deux couleurs HSL, le navigateur parcourt l'arc le plus court du cercle de teinte. Si vous allez d'un rouge chaud (hsl(10, 100%, 50%)) à un bleu frais (hsl(220, 100%, 50%)), le chemin le plus court passe par le violet — ce qui peut ou non être ce que vous souhaitez.

Mais le problème plus profond est que la Luminosité de HSL n'est pas perceptuellement uniforme. Un jaune à hsl(60, 100%, 50%) semble beaucoup plus brillant qu'un bleu à hsl(240, 100%, 50%), même s'ils partagent la même valeur L. Lorsque vous interpolez du jaune au bleu en HSL, la luminosité perçue plonge et vacille d'une manière qui semble incohérente.

/* Dégradé HSL — luminosité perceptuelle inégale selon les teintes */
background: linear-gradient(in hsl, hsl(60 100% 50%), hsl(240 100% 50%));

Le point médian de ce dégradé à hsl(150, 100%, 50%) est un vert vif qui semble perceptuellement plus lumineux que l'une ou l'autre des extrémités. Le dégradé culmine au milieu plutôt que de transiter en douceur.

L'interpolation HSL présente également un problème d'arc long : l'angle de teinte boucle à 360°, et si vous interpolez de hsl(350, ...) (proche du rouge) à hsl(20, ...) (orange), HSL peut parcourir le long chemin autour du cercle de teinte à travers le bleu, le vert et le jaune plutôt que le chemin court à travers le rouge.

OKLCH : cohérence et uniformité perceptuelle

OKLCH est une forme cylindrique de l'espace de couleur Oklab, conçu par Björn Ottosson en 2020 spécifiquement pour remédier aux lacunes d'uniformité perceptuelle des espaces de couleur antérieurs. Ses trois canaux — L (luminosité), C (chroma) et H (angle de teinte) — sont calibrés de sorte que des changements numériques égaux de L produisent des changements égaux de luminosité perçue, quelle que soit la teinte.

Lorsque vous interpolez entre deux couleurs OKLCH, vous obtenez :

  1. Luminosité perçue cohérente tout au long de la transition — pas d'affaissement vers des points médians sombres ni de pics lumineux brusques.
  2. Chroma préservée — les points médians restent vifs car la chroma est interpolée indépendamment de la teinte.
  3. Chemins de teinte plus courts et plus intuitifs — les angles de teinte d'OKLCH sont distribués dans l'ordre perceptuel, de sorte que l'interpolation passe par les teintes intermédiaires attendues.
/* Dégradé OKLCH — vif, perceptuellement uniforme */
background: linear-gradient(in oklch, red, blue);

Un dégradé du rouge au bleu en OKLCH passe par le magenta vif et le violet — les points médians perceptuellement intuitifs. Il reste saturé et uniformément brillant du début à la fin.

Comparaison côte à côte

Dégradé Couleur du point médian Qualité perçue
in srgb du rouge au vert #808000 — olive terne Vallée boueuse et sombre
in hsl du jaune au bleu Pic de vert vif Luminosité inégale, pic de couleur
in oklch du rouge au vert Jaune chaud vif Fluide, saturé, uniforme

Pour voir la différence par vous-même, utilisez le Générateur de dégradé qui vous permet de prévisualiser les dégradés dans différents espaces de couleur.

Comment convertir vos couleurs en OKLCH

Vous n'avez pas besoin de réécrire chaque valeur de couleur dans votre CSS. Le drapeau in oklch sur un dégradé indique au navigateur de convertir les couleurs des extrémités en OKLCH avant d'interpoler, puis de les reconvertir dans l'espace de couleur de sortie. Vous pouvez conserver vos valeurs HEX :

/* Ces extrémités HEX sont automatiquement converties en OKLCH pour l'interpolation */
background: linear-gradient(in oklch, #FF5733, #3498DB);

#FF5733 est approximativement oklch(0.63 0.24 27) et #3498DB est approximativement oklch(0.63 0.14 232). Utilisez le Convertisseur de couleur pour vérifier les valeurs OKLCH de n'importe quel code HEX avant de concevoir un dégradé, afin de savoir à l'avance ce que l'interpolation traversera.

La fonction color-mix()

CSS color-mix() est l'API déclarative pour mélanger deux couleurs, disponible dans tous les navigateurs modernes depuis 2023. Sa syntaxe inclut l'espace de couleur d'interpolation comme premier argument :

color: color-mix(in oklch, #FF5733 50%, #3498DB);

Cela mélange #FF5733 et #3498DB à proportions égales dans l'espace OKLCH. Le résultat est un intermédiaire vif qui ressemble à un vrai point médian perceptuel entre les deux couleurs — pas à une moyenne sRGB terne.

Utilisations pratiques de color-mix()

Créer des variantes transparentes :

:root {
  --brand: #2563EB;
  --brand-10: color-mix(in oklch, var(--brand) 10%, transparent);
  --brand-20: color-mix(in oklch, var(--brand) 20%, transparent);
  --brand-50: color-mix(in oklch, var(--brand) 50%, transparent);
}

Teinter vers le blanc ou le noir :

:root {
  --brand: #2563EB;
  --brand-light: color-mix(in oklch, var(--brand) 70%, white);
  --brand-dark:  color-mix(in oklch, var(--brand) 70%, black);
}

C'est la même idée qu'un générateur de nuances mais entièrement en CSS, sans prétraitement. Le résultat du teintage en OKLCH semble plus naturel que les opérations équivalentes en HSL car la chroma évolue de façon appropriée à l'approche du blanc ou du noir.

Dérivation d'état de survol :

.button {
  background: var(--brand);
}
.button:hover {
  background: color-mix(in oklch, var(--brand) 80%, black);
}

Attention : color-mix() en sRGB

Si vous omettez l'argument in <colorspace>, color-mix() utilise par défaut l'interpolation sRGB :

/* Cela utilise sRGB — peut produire des résultats ternes */
color: color-mix(#FF5733, #3498DB);

/* Correct : spécifier l'espace */
color: color-mix(in oklch, #FF5733, #3498DB);

Spécifiez toujours in oklch (ou un autre espace préféré) explicitement. Le sRGB par défaut est conservé pour la compatibilité ascendante mais est rarement le meilleur choix.

Espace de couleur d'interpolation des dégradés

La syntaxe CSS moderne vous permet de spécifier l'espace de couleur d'interpolation directement dans une déclaration de dégradé en utilisant in <colorspace> après le mot-clé de direction :

/* sRGB (par défaut, souvent terne) */
background: linear-gradient(to right, red, blue);

/* sRGB linéaire (meilleure luminance, toujours des problèmes de teinte) */
background: linear-gradient(in srgb-linear to right, red, blue);

/* HSL (décalages de teinte, luminosité inégale) */
background: linear-gradient(in hsl to right, red, blue);

/* OKLCH (recommandé : vif, perceptuellement uniforme) */
background: linear-gradient(in oklch to right, red, blue);

/* Oklab (également excellent, syntaxe moins intuitive) */
background: linear-gradient(in oklab to right, red, blue);

Cette syntaxe s'applique à tous les types de dégradé : linear-gradient, radial-gradient et conic-gradient.

Direction d'interpolation de teinte en OKLCH

Pour l'interpolation de teinte spécifiquement, vous pouvez contrôler si le dégradé prend l'arc le plus court ou le plus long autour du cercle de teinte :

/* Arc le plus court (par défaut) */
background: linear-gradient(in oklch, hsl(30 100% 50%), hsl(270 100% 50%));

/* Arc le plus long — passe par le jaune, le vert, le cyan, puis le violet */
background: linear-gradient(in oklch longer hue, hsl(30 100% 50%), hsl(270 100% 50%));

/* Arc croissant — va toujours dans le sens des angles de teinte croissants */
background: linear-gradient(in oklch increasing hue, hsl(30 100% 50%), hsl(270 100% 50%));

Le mot-clé shorter hue (par défaut) donne le résultat le plus naturel dans la plupart des cas. La variante longer hue est utile pour les effets arc-en-ciel ou lorsque vous souhaitez spécifiquement que le dégradé traverse une grande partie du spectre de teinte.

Dégradés multi-arrêts

L'interpolation OKLCH devient encore plus précieuse pour les dégradés multi-arrêts, car chaque segment interpole à travers des points médians perceptuellement vifs :

/* Un dégradé arc-en-ciel qui reste vif du début à la fin */
background: linear-gradient(
  in oklch to right,
  oklch(0.70 0.20 30),   /* orange-rouge */
  oklch(0.80 0.20 90),   /* jaune */
  oklch(0.75 0.20 150),  /* vert */
  oklch(0.65 0.20 240),  /* bleu */
  oklch(0.60 0.20 300)   /* violet */
);

Parce que les valeurs L et C sont calibrées perceptuellement, les régler à des valeurs similaires sur tous les arrêts produit un arc-en-ciel qui semble naturellement brillant et saturé, sans les creux de luminance courants dans les arcs-en-ciel sRGB.

Prise en charge des navigateurs

La syntaxe de dégradé in <colorspace> est prise en charge dans tous les principaux navigateurs :

  • Chrome/Edge : prise en charge complète depuis la version 111 (mars 2023)
  • Firefox : prise en charge complète depuis la version 113 (mai 2023)
  • Safari : prise en charge complète depuis la version 16.2 (décembre 2022)

Pour les anciens navigateurs, effectuez une dégradation gracieuse avec la syntaxe héritée en premier :

/* Repli : dégradé sRGB */
background: linear-gradient(to right, #FF5733, #3498DB);

/* Moderne : interpolation OKLCH */
@supports (background: linear-gradient(in oklch, red, blue)) {
  background: linear-gradient(in oklch to right, #FF5733, #3498DB);
}

Points clés

  • L'interpolation sRGB (la valeur par défaut CSS) produit des points médians ternes et désaturés quand les dégradés passent près du centre du cube sRGB — particulièrement visible dans les dégradés rouge-vert et les dégradés de couleurs complémentaires.
  • L'interpolation HSL évite certains problèmes RGB mais introduit une luminosité perçue incohérente — son canal Luminosité n'est pas perceptuellement uniforme — et peut produire des chemins de teinte inattendus.
  • L'interpolation OKLCH produit des points médians vifs et perceptuellement cohérents car elle a été conçue autour de la vision humaine. Les dégradés en OKLCH restent saturés et uniformément brillants sur toute leur plage.
  • Utilisez in oklch dans tout dégradé : linear-gradient(in oklch to right, red, blue). Utilisez color-mix(in oklch, color1 50%, color2) pour le mélange programmatique.
  • Le Convertisseur de couleur vous permet de convertir les valeurs HEX ou RGB en OKLCH afin de comprendre comment vos couleurs vont s'interpoler avant de valider un design de dégradé.
  • Le Générateur de dégradé vous permet de prévisualiser comment différents espaces de couleur affectent la sortie du dégradé pour n'importe quelle paire de couleurs.
  • La direction d'interpolation de teinte peut être contrôlée avec les mots-clés shorter hue, longer hue, increasing hue et decreasing hue — utiles pour les effets arc-en-ciel et le contrôle précis des dégradés multi-arrêts.

Couleurs associées

Marques associées

Outils associés