Syntaxe des couleurs relatives au CSS

Créer de nouvelles 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 du niveau de couleur CSS 5. La syntaxe de couleur relative crée un chemin lisse pour la manipulation des couleurs dans CSS, offrant ainsi aux auteurs et aux graphistes la possibilité de:

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 HSL, et les assembler dans une couleur finale et une couleur de variante finale. Cela signifie gérer de nombreuses pièces de couleur, ce qui peut rapidement devenir fastidieux.

: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 l'espace colorimétrique ou la syntaxe dont vous avez besoin, puis 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 à découvrir la syntaxe et à démontrer les manipulations de couleur courantes.

Si vous préférez la vidéo, presque tout l'article suivant est traité dans ce défi IUG.

Présentation de la syntaxe

L'objectif de la syntaxe de couleur relative est de permettre la dérivation d'une couleur à partir d'une autre couleur. 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 effectue une conversion, décompose cette couleur d'origine et propose les parties en tant que variables à utiliser dans la nouvelle définition de couleur.

Un schéma de la syntaxe RVB(du vert r g b / alpha) est illustré, avec une flèche qui quitte le haut du vert et forme une arche au début de la fonction RVB. Cette flèche se divise en 4 flèches qui pointent ensuite vers la variable correspondante. Les quatre flèches sont rouge, verte, bleue et alpha. Le rouge et le bleu ont la valeur 0, le vert est 128 et l'alpha 100%.

Le schéma précédent montre la couleur d'origine green convertie dans l'espace colorimétrique de la nouvelle couleur, transformée en nombres individuels représentés par des variables r, g, b et alpha, qui sont ensuite directement utilisés comme valeurs d'une 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 inchangée, ce qui génère toujours une couleur verte.

Mot clé from

La première partie de la syntaxe à apprendre est la partie from <color>, qui vient compléter la spécification d'une couleur. Elle va juste avant de spécifier les valeurs. Voici un exemple de code dans lequel seul from green a été ajouté, juste avant que les valeurs de rgb() 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, lorsqu'il est considéré comme le premier paramètre de la notation fonctionnelle, transforme la définition de la couleur en une couleur relative. Après le mot clé from, le CSS attend une couleur, c'est-à-dire une couleur qui inspirera la couleur suivante.

Conversion de couleur

Pour faire simple, elle convertit le vert en canaux r g et b pour une utilisation 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 des couleurs relatives offrent une si bonne correspondance, car vous pouvez résoudre le mystère de la couleur from. De plus, vous n'avez généralement pas besoin de connaître le format de 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 colorimétrique de votre choix

Vous pouvez choisir l'espace colorimétrique avec 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, comme 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 colorimétrique est également stimulante, car le choix d'un espace de couleur a tendance à se concentrer davantage sur le type d'alternance de couleurs qu'il ne s'agit d'une préférence. La préférence figure dans les résultats, et non dans le format de couleur ou les types de canaux. Cela deviendra beaucoup plus clair dans les sections de 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

Quelque chose d'étrange, mais d'intéressant dans cette syntaxe : les variables n'ont pas besoin d'ê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é en tant que variable nommée alpha. Il est facultatif et vient après / dans la notation des couleurs fonctionnelle.

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 encore et encore. Apprendre la syntaxe, et 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 soit différente de l'entrée.

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

Le temps est bleu marine maintenant ! La teinte a été doublée, en prenant une teinte de 120 et en la transformant en 240, modifiant complètement la couleur. Cela a fait pivoter la teinte le long de la roue chromatique, une astuce très simple simplifiée grâce aux espaces de couleurs cylindriques tels que HSL, HWB, LCH et OKLCH.

Pour visualiser les valeurs des canaux afin d'obtenir des calculs précis sans avoir à deviner les spécifications ni les mémoriser, essayez cet outil d'utilisation des valeurs de canaux basées sur la syntaxe des couleurs relatives. Il révèle chaque valeur de canal en fonction de la syntaxe que vous spécifiez, ce qui vous permet de savoir exactement avec quelles valeurs vous pouvez jouer.

Vérifier la compatibilité du 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 autres syntaxes pour obtenir des résultats similaires ou identiques. Les variantes proviennent des espaces de couleurs et des canaux qu'elles proposent.

En outre, de nombreux exemples montrent des ajustements de couleur avec le verbiage de by et to. Un by de couleur modifiée est un changement de couleur relatif. Il s'agit d'une modification qui utilise la valeur de la variable et effectue un ajustement en fonction de sa valeur actuelle. Un to qui a changé de couleur est un changement de couleur absolu. Il s'agit d'un changement qui n'utilise pas la valeur de la variable, mais spécifie une valeur entièrement nouvelle.

Toutes les démonstrations sont disponibles dans cette collection Codepen.

Éclaircir une couleur

Les espaces de couleurs OKLCH, OKLAB, XYZ ou sRGB fournissent les résultats les plus prévisibles lors de l'éclaircissement des couleurs.

Éclaircir d'une certaine quantité

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. Cela pousse la luminosité bleue vers le blanc de 25%.

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

Éclaircir selon une valeur spécifique

L'exemple .lighten-to-75 suivant n'utilise pas le canal l pour éclaircir blue, mais 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 couleur, qui sont efficaces pour éclaircir une couleur, sont également parfaits pour assombrir la couleur.

Assombrir selon une certaine quantité

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. Cela pousse la couleur bleue vers le noir de 25%.

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

Assombrir selon une valeur spécifiée

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

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

Saturer une couleur

Saturer selon un certain montant

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

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

Saturer jusqu'à une certaine quantité

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

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

Désaturer une couleur

Désaturer d'une certaine quantité

L'exemple .desaturate-by-half suivant utilise la 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 le désaturer d'une certaine quantité, vous pouvez le désaturer jusqu'à atteindre la 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);
}

Augmenter la chrominance d'une couleur

Cet effet est semblable à la saturation d'une couleur, mais il est différent à plusieurs égards. Tout d'abord, il s'agit d'une modification de chroma et non d'une modification de saturation, car les espaces de couleur qui peuvent être amplifiés dans une plage dynamique élevée n'utilisent pas la saturation. Les espaces de couleur dotés de chroma sont capables de fournir une plage dynamique élevée, ce qui permet aux auteurs d'améliorer l'éclat des couleurs au-delà de la saturation.

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

Ajuster l'opacité d'une couleur

La création d'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. Consultez l'exemple de l'introduction de cet article si vous l'avez manqué, il décrit très bien l'espace problématique.

Ajuster l'opacité selon une quantité

.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 de 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 des teintes est probablement ce que vous recherchez. Choisissez un espace de couleur qui propose la teinte comme angle, puis utilisez calc() pour faire pivoter la teinte selon la valeur souhaitée. Pour trouver le complément d'une couleur, effectuez une rotation d'un demi-tour. Dans ce cas, vous pouvez ajouter ou soustraire du canal h avec 180 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, envisagez la méthode L&midast; (Lstar). Cette méthode utilise le canal L (de luminosité uniforme globalement) de LCH et OKLCH dans une calc(). Selon que vous ciblez un contraste faible, moyen ou élevé, le delta du minimum est d'environ 40, ~50 ou ~60.

Cette technique fonctionne bien quelle que soit la teinte d'une teinte LCH ou OKLCH.

Contraster une couleur plus foncée

La classe .well-contrasting-darker-color illustre L* avec un delta de 60. Étant donné que la couleur d'origine est une couleur sombre (luminosité faible valeur), 60% (0,6) est ajouté au canal de luminosité. Cette technique permet de trouver une couleur de texte sombre bien contrastée, avec la même teinte 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 illustre également L* avec un delta de 60 %. Étant donné que la couleur d'origine est une couleur claire (luminosité de grande valeur), 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 des couleurs relatives est très efficace pour créer des palettes de couleurs. Elle est particulièrement utile et puissante en raison du nombre d'espaces de couleur disponibles. Les exemples suivants utilisent tous OKLCH, car le canal de luminosité est fiable et le canal de teinte peut être pivoté sans effets secondaires. Le dernier exemple illustre une combinaison d'ajustements de luminosité et de rotation des teintes, pour un résultat plus intéressant.

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

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

Palettes monochromes

Créer une palette monochrome consiste à utiliser la même teinte, mais avec des variations de luminosité et d'obscurité. La couleur du milieu est la couleur source de la palette, avec deux variantes plus claires et deux variantes plus sombres 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 plusieurs palettes créées avec une syntaxe de couleurs 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 construits sur une couleur que vous pouvez personnaliser, il vous suffit de lui attribuer une couleur et cela crée une palette !

Palettes analogues

Comme la rotation des teintes est très facile avec OKLCH et HSL, il est facile de créer une palette de couleurs analogue. Faites pivoter la teinte selon la valeur de votre choix et modifiez la couleur de base, puis observez la création de nouvelles palettes par le navigateur.

: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

À l'instar des couleurs complémentaires, les palettes de couleurs triadiques offrent des rotations de teintes opposées, mais harmonieuses en fonction d'une couleur de base. Lorsqu'une couleur complémentaire se trouve de l'autre côté d'une couleur, comme une ligne droite dessinée au milieu de la roue chromatique, les palettes triadiques ressemblent à un triangle de lignes, où deux couleurs ont une rotation égale par rapport à la couleur de base. Pour ce faire, faites pivoter la teinte 120deg.

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

: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 tradiques

Les palettes tétradiques sont quatre couleurs réparties équitablement autour de la roue chromatique, ce qui en fait une palette sans valeur dominante claire. Vous pouvez aussi le considérer comme deux paires de couleurs complémentaires. Utilisée à bon escient, elle peut être très significative.

Il s'agit d'une légère simplification de la théorie des couleurs, mais cela suffit pour vous lancer dans les palettes théâtrales plus complexes si cela vous intéresse.

: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));
}

Monochrome avec une légère rotation des teintes

De nombreux experts en couleurs tiennent ce tour dans leur étui. 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 à mesure que la luminosité est modifiée.

L'exemple suivant réduit la luminosité de 10% pour chaque échantillon et fait également pivoter la teinte de 10 degrés. Le résultat : une palette rose vif à indigo qui semble se fondre parfaitement, comme le pourrait le faire 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 avec OKLCH et rotation des teintes

L'interface de classement suivante utilise cette stratégie de rotation des teintes. Chaque élément de la liste suit son index dans le document en tant que variable appelée --i. Cet indice est ensuite utilisé pour ajuster la chrominance, la luminosité et la teinte. L'ajustement n'est que de 5% ou 5deg, ce qui est beaucoup plus subtil que l'exemple ci-dessus avec deeppink. Il est donc nécessaire de remarquer la raison pour laquelle ce classement peut être dans n'importe quelle teinte avec une telle élégance.

Veillez à modifier la teinte dans le curseur situé sous le classement et observez la syntaxe de couleur relative pour créer de magnifiques moments de couleurs.

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))
  );
}