Syntaxe des couleurs relatives au CSS

Créez des couleurs en fonction des canaux et des valeurs d'une autre couleur.

Adam Argyle
Adam Argyle

Dans Chrome 119, il s'agit d'une fonctionnalité de couleur très puissante issue du niveau de couleur CSS 5. La syntaxe de couleur relative crée un chemin fluide pour la manipulation des couleurs dans le CSS, offrant aux auteurs et aux concepteurs les possibilités suivantes:

Avant la syntaxe de couleur relative, pour modifier l'opacité d'une couleur, vous devez créer des propriétés personnalisées pour les canaux d'une couleur, généralement TSL, et les assembler en une couleur finale et une couleur de variante finale. Cela implique de gérer de nombreux éléments de couleur, ce qui peut rapidement devenir lourd.

:root {
  --brand-hue: 300deg;
  --brand-saturation: 75%;
  --brand-lightness: 50%;

  --brand-hsl:
    var(--brand-hue)
    var(--brand-saturation)
    var(--brand-lightness);

  --brand-color: hsl(var(--brand-hsl));

  /* all this work just so I can set the opacity to 50% in a variant */
  --brand-color-variant: hsl(var(--brand-hsl) / 50%);
}

Après la syntaxe de couleur relative, vous pouvez créer une couleur de marque avec n'importe quel espace de couleur ou syntaxe dont vous avez besoin, et créer une variante à demi-opacité avec beaucoup moins de code. Il est également beaucoup plus facile de lire l'intention des styles et du système.

:root {
  --brand-color: hsl(300deg 75% 50%);
  --brand-color-variant: hsl(from var(--brand-color) h s l / 50%);
}

Cet article vous aidera à apprendre la syntaxe et à démonstrer les manipulations de couleurs courantes.

Si vous préférez le format vidéo, presque tout l'article suivant est abordé dans ce défi de GUI.

Présentation de la syntaxe

L'objectif de la syntaxe des couleurs relatives est de permettre de dériver une couleur à partir d'une autre. La couleur de base est appelée couleur d'origine. Il s'agit de la couleur qui suit le nouveau mot clé from. Le navigateur convertit et scinde cette couleur d'origine, puis propose les parties en tant que variables à utiliser dans la nouvelle définition de couleur.

Un schéma de la syntaxe rgb(à partir du vert r g b / alpha) est affiché, avec une flèche partant du haut du vert et s'arcbutant dans le début de la fonction rgb. Cette flèche se divise en quatre flèches qui pointent ensuite vers leur variable appropriée. Les quatre flèches sont rouges, vertes, bleues et alpha. Le rouge et le bleu ont une valeur de 0, le vert est de 128 et l'alpha est de 100%.

Le diagramme précédent montre comment la couleur d'origine green est convertie en espace colorimétrique de la nouvelle couleur, puis transformée en nombres individuels représentés par des variables r, g, b et alpha, qui sont ensuite utilisés directement comme valeurs de la nouvelle couleur rgb().

Bien que cette image montre la répartition, le processus et les variables, elle ne modifie pas non plus la couleur. Les variables sont remises dans la couleur sans modification, ce qui donne toujours une couleur verte.

Le mot clé from

La première partie de la syntaxe à apprendre est l'ajout de from <color> pour spécifier une couleur. Il se trouve juste avant que vous spécifiiez les valeurs. Voici un exemple de code où seul from green a été ajouté, juste avant que les valeurs de rgb() ne soient spécifiées.

.syntax-introduction_same-colors {
  color: green;
  color: rgb(0 128 0);
  color: rgb(from green r g b);    /* result = rgb(0 128 0) */
}

Ce mot clé from, considéré comme le premier paramètre dans la notation fonctionnelle, transforme la définition de la couleur en couleur relative. Après le mot clé from, le CSS attend une couleur, une couleur qui inspirera la couleur suivante.

Conversion des couleurs

En d'autres termes, il convertit le vert en canaux r, g et b pour l'utiliser dans une nouvelle couleur.

rgb(from green r g b)           /* r=0 g=128 b=0 */
rgb(from rgb(0 128 0) r g b);   /* r=0 g=128 b=0 */

Couleurs des propriétés personnalisées

La lecture de rgb from green est très claire et facile à comprendre. C'est pourquoi les propriétés personnalisées et la syntaxe de couleur relative sont si bien assorties, car vous pouvez lever le mystère de la couleur from. En règle générale, vous n'avez pas besoin de connaître le format de couleur de la couleur de la propriété personnalisée, car vous créez une couleur dans le format de votre choix.

rgb(from rgb(255 105 180) r g b) /* ????? */
rgb(from var(--hotpink) r g b)   /* clear */

Travailler dans l'espace de couleur de votre choix

Vous pouvez choisir l'espace de couleurs en fonction de la notation de couleur fonctionnelle de votre choix.

rgb(from hsl(120 100% 25%) r g b)     /*  r=0   g=128  b=0    */
hsl(from hsl(120 100% 25%) h s l)     /*  h=120 s=100% l=25%  */
hwb(from hsl(120 100% 25%) h w b)     /*  h=120 w=0%   b=50%  */
lch(from hsl(120 100% 25%) l c h)     /*  l=46  c=68   h=134  */

La syntaxe de couleur relative comporte cette étape de conversion. La couleur après from est convertie dans l'espace colorimétrique spécifié au début de la couleur relative. L'entrée et la sortie n'ont pas besoin de correspondre, ce qui est très libérateur.

La possibilité de choisir un espace de couleurs est également enrichissante, car elle tend à se concentrer davantage sur le type d'alternance des couleurs que sur une préférence. La préférence se trouve dans les résultats, et non dans le format de couleur ni les types de canaux. Cela deviendra beaucoup plus clair dans les sections présentant les cas d'utilisation, car les différents espaces de couleurs excellent dans différentes tâches.

Combiner, faire correspondre, omettre et répéter les variables

Cette syntaxe présente une particularité étrange, mais intéressante : les variables ne doivent pas être remises dans l'ordre et peuvent être répétées.

rgb(from green g g g)    /* rgb(128 128 128) */
rgb(from green b r g)    /* rgb(0 0 128) */
rgb(from green 0 0 g)    /* rgb(0 0 128) */

Opacité en tant que variable

La syntaxe fournit également l'opacité sous la forme d'une variable nommée alpha. Il est facultatif et se place après le / dans la notation fonctionnelle des couleurs.

rgb(from #00800080 r g b / alpha)             /* alpha=50% */
rgb(from rgba(0,128,0,.5) r g b / alpha)      /* alpha=50% */
rgb(from rgb(0 128 0 / 50%) r g b / alpha)    /* alpha=50% */

Utiliser calc() ou d'autres fonctions CSS sur les variables

Jusqu'à présent, nous avons créé la couleur verte à plusieurs reprises. Apprendre la syntaxe, se familiariser avec les étapes de conversion et de déstructuration. Il est maintenant temps de modifier les variables et de modifier la sortie pour qu'elle ne soit pas identique à l'entrée.

green                              /*  h=120 s=100% l=25%  */
hsl(from green calc(h * 2) s l)    /*  h=240 s=100% l=25%  */

Il est maintenant bleu marine. La teinte a été doublée, en prenant une teinte de 120 et en la transformant en 240, ce qui a complètement modifié la couleur. Cela a fait pivoter la teinte sur la roue de couleur, un tour de passe-passe astucieux rendu très simple avec les espaces de couleurs cylindriques tels que HSL, HWB, LCH et OKLCH.

Pour voir visuellement les valeurs des canaux afin de pouvoir effectuer les calculs de manière précise sans deviner ni mémoriser les spécifications, essayez cet outil de valeurs des canaux de syntaxe de couleur relative. Il affiche la valeur de chaque canal en fonction de la syntaxe que vous spécifiez, ce qui vous permet de savoir exactement quelles valeurs sont disponibles.

Vérifier la compatibilité avec le navigateur

@supports (color: rgb(from white r g b)) {
  /* safe to use relative color syntax */
}

Cas d'utilisation et démonstrations

Les exemples et cas d'utilisation suivants proposent de nombreuses syntaxes alternatives pour obtenir des résultats similaires ou identiques. Les variations proviennent des espaces de couleurs et des canaux qu'ils proposent.

De plus, de nombreux exemples montrent des ajustements de couleur avec le langage by et to. Une couleur modifiée by est une modification de couleur relative, c'est-à-dire une modification qui utilise la valeur de la variable et effectue un ajustement en fonction de sa valeur actuelle. Une modification de couleur to est une modification de couleur absolue, c'est-à-dire une modification qui n'utilise pas la valeur de la variable, mais spécifie une valeur complètement nouvelle.

Vous trouverez toutes les démonstrations dans cette collection Codepen.

Éclaircir une couleur

Les espaces colorimétriques OKLCH, OKLAB, XYZ ou sRGB fournissent les résultats les plus prévisibles lorsque vous éclaircissez des couleurs.

Éclaircir d'un montant

L'exemple .lighten-by-25 suivant prend la couleur blue et la convertit en OKLCH, puis éclaircit le bleu en augmentant le canal l (luminosité) en multipliant la valeur actuelle par 1.25. La luminosité du bleu est ainsi poussée vers le blanc de 25%.

.lighten-by-25 {
  background: oklch(from blue calc(l * 1.25) c h);
}

Éclaircir jusqu'à une valeur spécifique

L'exemple .lighten-to-75 suivant n'utilise pas le canal l pour éclaircir blue. Il remplace complètement la valeur par 75%.

.lighten-to-75 {
  background: oklch(from blue 75% c h);
}

Assombrir une couleur

Les mêmes espaces de couleurs qui éclaircissent une couleur sont également très efficaces pour l'assombrir.

Assombrir d'un montant

L'exemple .darken-by-25 suivant prend la couleur bleue et la convertit en OKLCH, puis assombrit le bleu en diminuant le canal l (luminosité) de 25% en multipliant la valeur par .75. La couleur bleue est ainsi poussée vers le noir de 25%.

.darken-by-25 {
  background: oklch(from blue calc(l * .75) c h);
}

Assombrir jusqu'à une valeur spécifiée

L'exemple .darken-to-25 suivant n'utilise pas le canal l pour assombrir blue. Il remplace plutôt complètement la valeur par 25%.

.darken-to-25 {
  background: oklch(from blue 25% c h);
}
.

Saturer une couleur

Saturer d'un montant

L'exemple .saturate-by-50 suivant utilise le s de hsl() pour augmenter la vibrance de orchid d'une 50% relative.

.saturate-by-50 {
  background: hsl(from orchid h calc(s * 1.5) l);
}

Saturer à une valeur spécifique

L'exemple .saturate-to-100 suivant n'utilise pas le canal s de hsl(), mais spécifie plutôt une valeur de saturation souhaitée. Dans cet exemple, la saturation est augmentée à 100%.

.saturate-to-100 {
  background: hsl(from orchid h 100% l);
}

Désaturer une couleur

Désaturer d'un montant

L'exemple .desaturate-by-half suivant utilise le s de hsl() pour réduire de moitié la saturation de indigo.

.desaturate-by-half {
  background: hsl(from indigo h calc(s / 2) l);
}

Désaturer à une valeur spécifique

Plutôt que de désaturer d'une quantité, vous pouvez désaturer jusqu'à une valeur souhaitée spécifique. L'exemple .desaturate-to-25 suivant crée une couleur basée sur indigo, mais définit la saturation sur 25%.

.desaturate-to-25 {
  background: hsl(from indigo h 25% l);
}

Le boost chromatique d'une couleur

Cet effet est semblable à la saturation d'une couleur, mais il est différent à certains égards. Tout d'abord, il s'agit d'une modification chroma et non d'une modification saturation, car les espaces de couleurs pouvant être améliorés en plage dynamique élevée n'utilisent pas la saturation. Les espaces de couleurs qui comportent chroma sont compatibles avec la plage dynamique élevée, ce qui permet aux auteurs d'augmenter la vivacité des couleurs au-delà de la saturation.

.increase-chroma {
  background: oklch(from orange l calc(c + .1) h);
}

Ajuster l'opacité d'une couleur

Créer une variante semi-transparente d'une couleur est l'un des ajustements de couleur les plus courants effectués dans les systèmes de conception. Si vous l'avez manqué, consultez l'exemple de l'introduction de cet article. Il décrit très bien l'espace problème.

Ajuster l'opacité d'un montant

.decrease-opacity-by-25 {
  background: rgb(from lime r g b / calc(alpha / 2));
}

Ajuster l'opacité à une valeur spécifique

.decrease-opacity-to-25 {
  background: rgb(from lime r g b / 25%);
}

Inverser une couleur

L'inversion des couleurs est une fonction d'ajustement des couleurs courante dans les bibliothèques de couleurs. Pour ce faire, vous pouvez convertir une couleur en RVB, puis soustraire la valeur de chaque canal à 1.

.invert-each-rgb-channel {
  background: rgb(from yellow calc(255 - r) calc(255 - g) calc(255 - b));
}

Compléter une couleur

Si votre objectif n'était pas d'inverser une couleur, mais plutôt de la compléter, la rotation de la teinte est probablement ce que vous recherchez. Choisissez un espace de couleur qui propose la teinte sous la forme d'un angle, puis utilisez calc() pour faire pivoter la teinte d'un angle de votre choix. Pour trouver le complément d'une couleur, effectuez une demi-rotation. Dans ce cas, vous pouvez ajouter ou soustraire 180 au canal h pour obtenir le résultat.

.complementary-color {
  background: hsl(from blue calc(h + 180) s l);
}

Contraster une couleur

Pour obtenir des rapports de contraste des couleurs accessibles, utilisez L&midast; (Lstar). Il utilise le canal de luminosité (L) (approximativement) uniforme de LCH et OKLCH, dans un calc(). Selon que vous ciblez un contraste faible, moyen ou élevé, le delta L&midast; est d'environ 40, 50 ou 60.

Cette technique fonctionne bien pour toutes les teintes en LCH ou OKLCH.

Contraster une couleur plus sombre

La classe .well-contrasting-darker-color illustre L* avec un delta de 60. Étant donné que la couleur d'origine est sombre (valeur de luminosité faible), 60% (0,6) est ajouté au canal de luminosité. Cette technique permet de trouver une couleur de texte sombre de la même teinte et bien contrastée sur un fond clair.

.well-contrasting-darker-color {
  background: darkred;
  color: oklch(from darkred calc(l + .60) c h);
}
.

Contraster une couleur plus claire

La classe .well-contrasting-lighter-color présente également L* avec un delta de 60 %. Étant donné que la couleur d'origine est claire (valeur de luminosité élevée), 0,60 est soustrait du canal de luminosité.

.well-contrasting-lighter-color {
  background: lightpink;
  color: oklch(from lightpink calc(l - .60) c h);
}

Palettes de couleurs

La syntaxe de couleur relative est très efficace pour créer des palettes de couleurs. Il est particulièrement utile et puissant en raison du nombre d'espaces de couleurs disponibles. Les exemples suivants utilisent tous OKLCH, car le canal de luminosité est fiable et le canal de teinte peut être pivoté sans effet secondaire. L'exemple final illustre une combinaison d'ajustements de luminosité et de rotation de teinte pour un résultat plus intéressant.

Ouvrez l'exemple de code source pour ces éléments et essayez de modifier --base-color pour voir à quel point ces palettes sont dynamiques. C'est amusant !

Si vous aimez les vidéos, je vous propose des informations détaillées sur la création de palettes de couleurs en CSS avec OKLCH sur YouTube.

Palettes monochromes

Une palette monochrome est une palette composée de la même teinte, mais avec des variations de luminosité. La couleur du milieu est la couleur source de la palette, où deux variantes plus claires et deux plus sombres sont placées de chaque côté.

:root {
  --base-color: deeppink;

  --color-0: oklch(from var(--base-color) calc(l + .20) c h); /* lightest */
  --color-1: oklch(from var(--base-color) calc(l + .10) c h);
  --color-2: var(--base-color);
  --color-3: oklch(from var(--base-color) calc(l - .10) c h);
  --color-4: oklch(from var(--base-color) calc(l - .20) c h); /* darkest */
}
Essayez un grand nombre de palettes créées avec la syntaxe de couleur relative et OKLCH

Open Props, une bibliothèque de variables CSS sans frais, propose des palettes de couleurs créées avec cette stratégie et les rend facilement utilisables avec une importation. Ils sont également tous basés sur une couleur que vous pouvez personnaliser. Il vous suffit de lui donner une couleur pour qu'il génère une palette.

Palettes analogues

Étant donné que la rotation de la teinte est si simple avec OKLCH et HSL, il est facile de créer une palette de couleurs analogue. Faites pivoter la teinte d'une valeur qui vous convient, puis modifiez la couleur de base. Le navigateur crée alors de nouvelles palettes.

:root {
  --base-color: blue;

  --primary:   var(--base-color);
  --secondary: oklch(from var(--base-color) l c calc(h - 45));
  --tertiary:  oklch(from var(--base-color) l c calc(h + 45));
}

Palettes triadiques

Comme les couleurs complémentaires, les palettes de couleurs triadiques sont des rotations de teintes opposées, mais harmonieuses, à partir d'une couleur de base. Alors qu'une couleur complémentaire se trouve de l'autre côté d'une couleur, comme une ligne droite tracée au milieu de la roue des couleurs, les palettes triadiques sont comme un triangle de lignes, qui trouvent deux couleurs pivotées de manière égale à partir d'une couleur de base. Pour ce faire, faites pivoter la teinte 120deg.

Il s'agit d'une légère simplification de la théorie des couleurs, mais elle suffit à vous lancer dans les palettes triadiques plus complexes si vous le souhaitez.

:root {
  --base-color: yellow;
  --triad-1: oklch(from var(--base-color) l c calc(h - 120));
  --triad-2: oklch(from var(--base-color) l c calc(h + 120));
}

Palettes tétradics

Les palettes tétrades sont composées de quatre couleurs réparties uniformément autour de la roue des couleurs, ce qui donne une palette sans valeur dominante claire. Vous pouvez aussi considérer cela comme deux paires de couleurs complémentaires. Utilisé judicieusement, il peut être très utile.

Il s'agit d'une légère simplification de la théorie des couleurs, mais elle suffit à vous lancer dans les palettes tétrades plus complexes si vous le souhaitez.

:root {
  --base-color: lime;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) l c calc(h + 90));
  --color-3: oklch(from var(--base-color) l c calc(h + 180));
  --color-4: oklch(from var(--base-color) l c calc(h + 270));
}

Monochromatique avec une légère rotation de la teinte

De nombreux experts en couleurs ont recours à cette astuce. Le problème est qu'une échelle de couleurs monochrome peut être assez ennuyeuse. La solution consiste à ajouter une rotation de teinte mineure ou majeure à chaque nouvelle couleur lorsque la luminosité est modifiée.

L'exemple suivant réduit la luminosité de 10% pour chaque nuance et fait également pivoter la teinte de 10 degrés. Le résultat est une palette allant du rose vif à l'indigo qui semble se fondre parfaitement, comme un dégradé.

:root {
  --base-color: deeppink;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) calc(l - .10) c calc(h - 10));
  --color-3: oklch(from var(--base-color) calc(l - .20) c calc(h - 20));
  --color-4: oklch(from var(--base-color) calc(l - .30) c calc(h - 30));
  --color-5: oklch(from var(--base-color) calc(l - .40) c calc(h - 40));
}
Essayez ce classement créé avec OKLCH et la rotation de la teinte

L'interface du classement suivant utilise cette stratégie de rotation des teintes. Chaque élément de liste suit son index dans le document en tant que variable appelée --i. Cet indice est ensuite utilisé pour ajuster la chromie, la luminosité et la teinte. L'ajustement n'est que de 5% ou 5 degrés, beaucoup plus subtil que l'exemple ci-dessus avec le rose foncé. Il faut donc un œil attentif pour remarquer pourquoi ce classement peut être de n'importe quelle teinte avec une telle élégance.

Veillez à modifier la teinte dans le curseur sous le classement, et découvrez comment la syntaxe de couleur relative crée de beaux moments de couleur.

li {
  --_bg: oklch(
    /* decrease lightness as list grows */
    calc(75% - (var(--i) * 5%))

    /* decrease chroma as list grows */
    calc(.2 - (var(--i) * .01))

    /* lightly rotate the hue as the list grows */
    calc(var(--hue) - (var(--i) + 5))
  );
}