Accéder au contenu principal

7min.

Les couleurs relatives en CSS 🎹

Je ne sais pas vous, mais une chose qui m’a toujours frustrĂ© en tant que dĂ©veloppeur front-end, c’est de devoir manipuler des couleurs.

Appliquer une opacitĂ©, ajuster une teinte ou modifier la luminositĂ© d’une couleur selon un contexte donnĂ© a toujours Ă©tĂ© un exercice dĂ©licat. 😕

Pendant trĂšs longtemps, l’unique solution consistait Ă  utiliser un prĂ©processeur tel que Sass, proposant diverses fonctions liĂ©es aux couleurs (darken(), lighten(), etc.).

Puis, l’arrivĂ©e des propriĂ©tĂ©s personnalisĂ©es a marquĂ© un tournant majeur dans la conception des interfaces web.

NĂ©anmoins, manipuler une couleur restait encore et toujours un processus laborieux
 et ce, jusqu’à l’arrivĂ©e des couleurs relatives, introduites par le CSS Color Module Level 5 du W3C ! 🎉

Mais, avant d’entrer dans le vif du sujet, je vous propose de faire un bref retour en arriĂšre sur la façon de manipuler une couleur, Ă  une Ă©poque, pas si lointaine, afin de mieux apprĂ©hender les problĂ©matiques qui y sont liĂ©es. 🙄

Section intitulĂ©e le-monde-d-avantLe monde d’avant 🩖

Commençons par dĂ©finir la couleur principale de notre thĂšme Ă  l’aide d’une propriĂ©tĂ© personnalisĂ©e, laquelle est dĂ©finie globalement via la pseudo-classe :root :

:root {
  --brand-color: #e23e57;
}

Utilisons maintenant cette propriĂ©tĂ© personnalisĂ©e pour modifier la couleur de fond d’un bouton :

.button {
  background-color: var(--brand-color);
}

Jusqu’ici tout va bien ! 😇

Nous souhaitons dĂ©sormais changer l’apparence de notre bouton lorsqu’il est survolĂ© par un pointeur (Ă©tat :hover).

Une bonne pratique est d’ajuster la luminositĂ© de la couleur de fond du bouton afin de la rendre plus sombre :

Afin de corser l’exercice, la couleur de fond du bouton survolĂ© doit ĂȘtre relative Ă  sa couleur de fond courante (il n’est donc pas question d’ajouter arbitrairement une nouvelle couleur de fond spĂ©cifique Ă  l’état :hover).

Vous me voyez venir ? Oui, les problùmes commencent maintenant ! 😈

Section intitulée problematiquesProblématiques

Afin de rĂ©pondre Ă  cette problĂ©matique, une des solutions consiste Ă  utiliser l’espace colorimĂ©trique hsl(), puis, Ă  dĂ©finir chaque composante de cette couleur (teinte, saturation et luminositĂ©) au sein d’une propriĂ©tĂ© personnalisĂ©e dĂ©diĂ©e, comme ceci :

:root {
  --brand-color-hue: 351deg;
  --brand-color-saturation: 74%;
  --brand-color-lightness: 56%;
}

Nous pouvons alors modifier la composante de luminositĂ© de la couleur de fond de notre bouton, indĂ©pendamment de ses deux autres composantes (teinte et saturation) :

.button {
  background-color: hsl(
    var(--brand-color-hue)
    var(--brand-color-saturation)
    var(--brand-color-lightness)
  );

  &:hover {
    --brand-color-lightness: 41%;
  }
}

Oui, mais


Cette approche prĂ©sente plusieurs inconvĂ©nients : ⚠

  1. Nous sommes dĂ©pendants de la notation fonctionnelle hsl() ;
  2. La composante de luminositĂ© a Ă©tĂ© fixĂ©e arbitrairement Ă  41% (-15%), sans tenir compte de sa valeur initiale dĂ©finie Ă  56% ;
  3. Plus gĂ©nĂ©ralement, la complexitĂ© du code augmente significativement. Imaginez un projet comportant une dizaine de couleurs et des composants d’interface ayant plusieurs variations (bouton primaire, secondaire, etc.). Nous devrons gĂ©rer chaque composante de couleur sĂ©parĂ©ment, et ce, pour chaque couleur et chaque variation de composant d’interface. 🙃

Heureusement, il existe une solution beaucoup plus simple ! 🎉

Section intitulĂ©e bienvenue-aux-couleurs-relativesBienvenue aux couleurs relatives đŸ€—

DĂ©finissons d’abord ce qu’est une couleur relative :

Une couleur relative est une couleur basĂ©e sur une couleur existante. đŸ€Ż

Je sens la déception dans votre regard


Section intitulée syntaxeSyntaxe

La syntaxe pour dĂ©finir une couleur relative est assez simple :

color-function(from origin-color channel1 channel2 channel3 / alpha)

Plongeons un peu plus dans les dĂ©tails :

  • color-function() est la notation fonctionnelle utilisĂ©e pour manipuler les couleurs, comme rgb(), hsl(), hwb(), etc. ;
  • origin-color est, comme son nom l’indique, la couleur d’origine, elle doit ĂȘtre prĂ©cĂ©dĂ©e du mot-clĂ© from. La couleur relative se basera sur cette couleur ;
  • chanel1, chanel2 et chanel3 correspondent aux composantes de la couleur de sortie. Ces composantes sont liĂ©es Ă  la notation fonctionnelle color-function() utilisĂ©e pour la couleur relative ;
  • alpha est une valeur optionnelle qui reprĂ©sente le canal alpha (opacitĂ©) de la couleur.

Voici un premier exemple pour illustrer ça :

.button {
  background-color: rgb(from red r g b);
}

Dans cet exemple, notre couleur relative est définie avec la notation fonctionnelle rgb(). Les valeurs des composantes de sortie doivent donc suivre cet espace colorimétrique.

La couleur d’origine est, quant Ă  elle, dĂ©finie par le mot-clĂ© red.

Il est intĂ©ressant de noter que la couleur d’origine est nommĂ©e, alors que les composantes de la couleur de sortie suivent l’espace colorimĂ©trique rgb().

En rĂ©alitĂ©, le navigateur convertit la couleur d’origine dans l’espace colorimĂ©trique spĂ©cifiĂ© pour la couleur relative.

Enfin, les composantes de notre couleur de sortie restent inchangĂ©es (r g b) et sont donc identiques Ă  celles de la couleur d’origine :

  • La valeur de la composante rouge r de notre couleur de sortie est Ă©gale Ă  255 ;
  • La valeur de la composante verte g de notre couleur de sortie est Ă©gale Ă  0 ;
  • La valeur de la composante bleue b de notre couleur de sortie est Ă©gale Ă  0.

Le code CSS prĂ©cĂ©dent est Ă©quivalent Ă  celui-ci :

.button {
  background-color: red;
}

Oui, tout ça pour ça. 😅

Section intitulée quelques-exemples-interessantsQuelques exemples intéressants

Maintenant que vous avez saisi le principe, jouons au jeu des diffĂ©rences (indice, il y en a 2 🙄) :

.button {
  background-color: rgb(from red b g r);
}

Cette fois-ci, les composantes r et b de notre couleur de sortie ont été inversées (le filou).

Oui, il est possible de permuter (et mĂȘme de rĂ©pĂ©ter) les composantes de la couleur de sortie.

À votre avis, quelle sera la couleur de fond du bouton
 ? đŸ„

Un indice, l’exemple prĂ©cĂ©dent est Ă©quivalent Ă  :

.button {
  background-color: rgb(from rgb(255 0 0) b g r);
}

Ou encore :

.button {
  background-color: rgb(0 0 255);
}

Soit :

.button {
  background-color: blue;
}

Et oui, la couleur de fond du bouton sera donc bleue !

Amusons-nous maintenant Ă  modifier la valeur d’une des composantes de notre couleur de sortie :

.button {
  background-color: rgb(from red r g 255);
}

Cette fois-ci, nous avons défini la valeur de la composante bleue b de notre couleur de sortie à 255.

Ce code CSS est donc Ă©quivalent Ă  :

.button {
  background-color: rgb(255 0 255);
}

Soit du rouge pourpre
 du magenta pour les puristes, ou du violet pour moi 😅 :

.button {
  background-color: magenta;
}

Ou encore (lĂ , c’est juste pour mon plaisir personnel) :

.button {
  background-color: rgb(from red r g r);
}

C’est magique, non ? 🧙

Section intitulée utilisation-des-proprietes-personnaliseesUtilisation des propriétés personnalisées

Comme nous l’avons mentionnĂ© prĂ©cĂ©demment, il est possible d’utiliser un espace colorimĂ©trique diffĂ©rent entre la couleur d’origine et les composantes de la couleur de sortie.

Mais ce n’est pas tout, la couleur d’origine peut Ă©galement ĂȘtre stockĂ©e dans une propriĂ©tĂ© personnalisĂ©e, ou ĂȘtre spĂ©cifiĂ©e Ă  l’aide du mot-clĂ© currentcolor.

Pour reprendre notre tout premier exemple, cette Ă©criture est donc tout Ă  fait envisageable :

:root {
  --brand-color: #e23e57;
}

.button {
  background-color: hsl(from var(--brand-color) h s 41%);
}

Nous avons modifiĂ© la valeur de la composante de luminositĂ© de la couleur de sortie, dĂ©finie dans un espace colorimĂ©trique hsl(), Ă  partir de sa couleur d’origine, en notation hexadĂ©cimale, elle-mĂȘme stockĂ©e dans une propriĂ©tĂ© personnalisĂ©e. đŸ€Ż

Oui, ça commence Ă  ĂȘtre intĂ©ressant, mais le meilleur est Ă  venir ! 😄

Section intitulée utilisation-de-la-fonction-code-calc-codeUtilisation de la fonction calc()

Une fonctionnalitĂ© vraiment pratique serait de pouvoir modifier les valeurs des composantes de notre couleur de sortie, en se basant sur leurs valeurs initiales, qu’en pensez-vous ?

Bonne nouvelle, cette fonctionnalitĂ© est rendue possible grĂące Ă  la fonction calc() ! 🎉

Imaginons maintenant que nous souhaitions diminuer la valeur de la composante de luminositĂ© de 15%, par rapport Ă  celle de notre couleur d’origine ?

C’est maintenant possible en une seule dĂ©claration CSS :

.button {
  background-color: hsl(from var(--brand-color) h s calc(l - 15));
}

Et oui, tout simplement. 🙂

Notre tout premier exemple peut donc se simplifier de cette façon.

Avant :

:root {
  --brand-color-hue: 351deg;
  --brand-color-saturation: 74%;
  --brand-color-lightness: 56%;
}

.button {
  background-color: hsl(
    var(--brand-color-hue)
    var(--brand-color-saturation)
    var(--brand-color-lightness)
  );

  &:hover {
    --brand-color-lightness: 41%;
  }
}

AprĂšs :

:root {
  --brand-color: #e23e57;
}

.button {
  background-color: var(--brand-color);

  &:hover {
    background-color: hsl(from var(--brand-color) h s calc(l - 15));
  }
}

Nous avons rĂ©solu nos trois problĂ©matiques de dĂ©part, Ă  savoir :

  1. Nous sommes libres d’utiliser n’importe quel espace colorimĂ©trique pour dĂ©finir nos couleurs ;
  2. Il est dĂ©sormais possible de modifier la valeur d’une composante de la couleur de sortie en se basant sur sa valeur initiale Ă  l’aide de la fonction calc() ;
  3. Le code CSS est beaucoup plus simple et facile Ă  maintenir.

Section intitulĂ©e bonus-un-bouton-a-plusieurs-variationsBonus : Un bouton Ă  plusieurs variations ?

En apportant quelques modifications Ă  notre exemple prĂ©cĂ©dent, il est mĂȘme possible, en quelques lignes, d’ajouter des variations Ă  notre bouton đŸ€© :

.button--primary {
  --button-bg: #e23e57;
}

.button--secondary {
  --button-bg: #48a6a7;
}

.button--tertiary {
  --button-bg: #7f55b1;
}

.button {
  background-color: var(--button-bg);

  &:hover {
    background-color: hsl(from var(--button-bg) h s calc(l - 15));
  }
}

Section intitulée support-navigateurSupport navigateur

Une bonne nouvelle n’arrive jamais seule : Le support navigateur est trĂšs correct.

Cette fonctionnalitĂ© est supportĂ©e par les derniĂšres versions de Chrome, Firefox, Edge, Safari et Opera, raison de plus de l’adopter dĂšs maintenant ! đŸ„ł

Section intitulée le-mot-de-la-finLe mot de la fin

Bref, vous l’aurez compris, les couleurs relatives font parties des fonctionnalitĂ©s que j’attendais depuis de nombreuses annĂ©es.

Elles rĂ©pondent parfaitement Ă  mes besoins (gestion de thĂšmes personnalisĂ©s, manipulation de couleurs, etc.), et je pourrais difficilement m’en passer aujourd’hui.

J’espùre, en tout cas, que cela vous incitera à les essayer dans vos futurs projets ! 🙂

Commentaires et discussions

Ces clients ont profité de notre expertise