Présentation des principes de base de la création d'un jeu de couleurs dynamique et configurable
Dans cet article, je vais vous expliquer comment gérer plusieurs jeux de couleurs dans CSS. Tester la fonctionnalité
Si vous préférez la vidéo, voici une version YouTube de ce post:
Présentation
Nous allons créer un système de couleurs accessible avec des propriétés personnalisées et calc()
, afin de créer une page Web qui s'adapte aux préférences utilisateur tout en réduisant au maximum l'expérience de création. Nous commençons par une couleur de marque de base et créons un système de variantes à partir de celle-ci: deux couleurs de texte, quatre couleurs de surface et une ombre correspondante.
Ce guide commence par définir à l'avance toutes les couleurs de chaque jeu de couleurs. Ce n'est que la toute fin qu'ils servent à changer la page.
La marque
Souvent, une couleur de marque a déjà été établie et est proposée en tant que couleur hex ou rgb. La couleur de base de la marque de ce défi IUG est #0af
. Tout d'abord, pour ce système de couleurs, la valeur hexadécimale doit être convertie en hsl.
* {
--brand: #0af;
--brand: hsl(200 100% 50%);
}
Pour qu'un concept d'assombrissement ou d'éclaircissement de la couleur de la marque soit possible, par exemple, les trois canaux de la valeur de la couleur HSL doivent être extraits dans leurs propres propriétés personnalisées, comme ceci:
* {
--brand-hue: 200;
--brand-saturation: 100%;
--brand-lightness: 50%;
}
CSS peut effectuer des calculs sur ces propriétés de couleur (par exemple, calc(var(--brand-lightness) -
20%)
pour réduire la valeur de luminosité de 20 %). Cette étape est fondamentale pour créer un jeu de couleurs, car le CSS peut conserver toutes les couleurs dans la même famille de teintes en ajustant les valeurs de saturation et de luminosité de la technologie HSL.
Thème clair
Chaque variante de couleur est marquée avec son schéma de correspondance. Dans ce cas, chacune est associée à -light
.
Marque
À partir de la couleur de la marque, elle est recréée en encapsulant les propriétés personnalisées --brand-hue
, --brand-saturation
et --brand-lightness
à l'intérieur de la parenthèse de la fonction hsl ()
, sans aucun calcul:
* {
--brand-light: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
}
Couleurs du texte
Ensuite, les éléments essentiels d'un jeu de couleurs ont besoin de couleurs de texte. Dans un thème clair, le texte doit être très sombre. Notez que la luminosité des couleurs suivantes est faible (bien en dessous de 50 %).
* {
--text1-light: hsl(var(--brand-hue) var(--brand-saturation) 10%);
--text2-light: hsl(var(--brand-hue) 30% 30%);
}
--text1-light
, étant donné qu'il est très sombre à 10% de luminosité, maintient la saturation lourde de 100 % afin que la couleur de la marque apparaisse encore dans le bleu marine foncé.
--text2-light
, elle n'est pas aussi sombre que la première couleur, ce qui est bien, car il s'agit d'une couleur secondaire, et elle est également beaucoup moins saturée.
Couleurs de surface
Les couleurs de surface sont les arrière-plans, les bordures et les autres surfaces décoratives sur lesquels ou à l'intérieur du texte. Dans un thème clair, il s'agit des couleurs claires par opposition aux couleurs de texte, qui étaient sombres. Pour créer des couleurs claires avec hsl, nous utiliserons des valeurs de pourcentage plus élevées dans la troisième valeur de luminosité. Nous allons également réduire la saturation afin que les gris clair ne soient pas trop teintés.
* {
--surface1-light: hsl(var(--brand-hue) 25% 90%);
--surface2-light: hsl(var(--brand-hue) 20% 99%);
--surface3-light: hsl(var(--brand-hue) 20% 92%);
--surface4-light: hsl(var(--brand-hue) 20% 85%);
}
Quatre couleurs de surface ont été créées, car les couleurs décoratives ont tendance à nécessiter plus de variantes, pour les moments interactifs comme :focus
ou :hover
, ou pour créer l'apparence des calques de papier. Dans ces scénarios, il est utile de faire passer --surface2-light
lorsque l'utilisateur pointe sur --surface3-light
. Ainsi, ce type de survol augmente le contraste (de 99% à 92% de luminosité, ce qui la rend plus sombre).
Ombres
Les ombres d'un jeu de couleurs vont au-delà, mais ajoutent une nature réaliste à l'effet et l'aident à se démarquer des ombres noires irréalistes. Pour ce faire, la couleur de l'ombre utilisera la propriété personnalisée de teinte, sera légèrement saturée de teinte, mais toujours très sombre. Essentiellement, on crée une ombre très foncée, légèrement bleue.
* {
--surface-shadow-light: var(--brand-hue) 10% 20%;
--shadow-strength-light: .02;
}
--surface-shadow-light
n'est pas encapsulé dans une fonction hsl. En effet, la valeur --shadow-strength
est combinée pour créer une certaine opacité, et CSS a besoin de ces éléments pour effectuer des calculs. Pour en savoir plus, consultez la section Ombre radio.
Toutes les couleurs claires
Vous n'avez pas besoin de chercher comment les couleurs claires sont créées, elles se trouvent toutes au même endroit dans le CSS.
* {
--brand-light: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
--text1-light: hsl(var(--brand-hue) var(--brand-saturation) 10%);
--text2-light: hsl(var(--brand-hue) 30% 30%);
--surface1-light: hsl(var(--brand-hue) 25% 90%);
--surface2-light: hsl(var(--brand-hue) 20% 99%);
--surface3-light: hsl(var(--brand-hue) 20% 92%);
--surface4-light: hsl(var(--brand-hue) 20% 85%);
--surface-shadow-light: var(--brand-hue) 10% calc(var(--brand-lightness) / 5);
--shadow-strength-light: .02;
}
![capture d'écran montrant l'ensemble des couleurs claires](https://web.dev/static/articles/building/a-color-scheme/image/screenshot-the-light-col-72f65fca6bd79.png?authuser=5&hl=fr)
Thème sombre
La plupart des marques ne commencent pas par un thème sombre, mais une variante de leur thème principal, généralement plus clair. Les utilisateurs, quant à eux, choisissent souvent un thème sombre pour différents contextes, comme la nuit. Ces facteurs m'ont conduit à garder deux choses à l'esprit avec les thèmes sombres:
- Les utilisateurs seront généralement dans le noir lorsque vous utilisez ce thème. Testez donc dans l'obscurité.
- Les couleurs doivent se désaturer pour ne pas vibrer à l'écran en raison d'une trop grande intensité.
Marque
Le thème clair a utilisé les valeurs des trois canaux de couleur SSL de la marque sans modification, contrairement au thème sombre. La saturation est divisée de moitié et la luminosité a été réduite de 50 % environ.
* {
--brand-dark: hsl(
var(--brand-hue)
calc(var(--brand-saturation) / 2)
calc(var(--brand-lightness) / 1.5)
);
}
Couleurs du texte
Dans un thème sombre, les couleurs du texte doivent être claires. Les couleurs suivantes ont des valeurs de luminosité élevées, ce qui les rapproche du blanc.
* {
--text1-dark: hsl(var(--brand-hue) 15% 85%);
--text2-dark: hsl(var(--brand-hue) 5% 65%);
}
Couleurs de surface
Dans un thème sombre, les couleurs de surface doivent être sombres. Les couleurs suivantes présentent une faible luminosité et une saturation, la première surface étant la plus sombre à 10%.
* {
--surface1-dark: hsl(var(--brand-hue) 10% 10%);
--surface2-dark: hsl(var(--brand-hue) 10% 15%);
--surface3-dark: hsl(var(--brand-hue) 5% 20%);
--surface4-dark: hsl(var(--brand-hue) 5% 25%);
}
Ombres
Avec un thème sombre, les ombres peuvent être très difficiles à voir. C’est logique puisqu’il est difficile d’assombrir
quelque chose qui est déjà assez sombre. C'est là que --shadow-strength-dark
s'avère très pratique, car il nous permet d'assombrir les ombres en modifiant une variable.
* {
--surface-shadow-dark: var(--brand-hue) 50% 3%;
--shadow-strength-dark: .8;
}
Examinez également le niveau de saturation de cette ombre. Remarquez-vous la couleur lorsque vous regardez l'interface ? Essayez de supprimer la saturation des outils de développement, lequel préférez-vous ?
Des couleurs sombres réunies
* {
--brand-dark: hsl(var(--brand-hue) calc(var(--brand-saturation) / 2) calc(var(--brand-lightness) / 1.5));
--text1-dark: hsl(var(--brand-hue) 15% 85%);
--text2-dark: hsl(var(--brand-hue) 5% 65%);
--surface1-dark: hsl(var(--brand-hue) 10% 10%);
--surface2-dark: hsl(var(--brand-hue) 10% 15%);
--surface3-dark: hsl(var(--brand-hue) 5% 20%);
--surface4-dark: hsl(var(--brand-hue) 5% 25%);
--surface-shadow-dark: var(--brand-hue) 50% 3%;
--shadow-strength-dark: .8;
}
![capture d'écran des couleurs sombres réunies](https://web.dev/static/articles/building/a-color-scheme/image/screenshot-the-dark-colo-2883f3f94a6ae.png?authuser=5&hl=fr)
Réduire la luminosité du thème
Ce jeu de couleurs est axé sur l'orchestration de la luminosité et de la saturation. La saturation doit être suffisante pour que la teinte reste visible, mais les scores de contraste devraient être à peine transmis, car ils sont censés être sombres et peu contrastés.
Marque
* {
--brand-dim: hsl(
var(--brand-hue)
calc(var(--brand-saturation) / 1.25)
calc(var(--brand-lightness) / 1.25)
);
}
Couleurs du texte
* {
--text1-dim: hsl(var(--brand-hue) 15% 75%);
--text2-dim: hsl(var(--brand-hue) 10% 61%);
}
Couleurs de surface
* {
--surface1-dim: hsl(var(--brand-hue) 10% 20%);
--surface2-dim: hsl(var(--brand-hue) 10% 25%);
--surface3-dim: hsl(var(--brand-hue) 5% 30%);
--surface4-dim: hsl(var(--brand-hue) 5% 35%);
}
Ombres
* {
--surface-shadow-dim: var(--brand-hue) 30% 13%;
--shadow-strength-dim: .2;
}
Assombrir toutes les couleurs
* {
--brand-dim: hsl(var(--brand-hue) calc(var(--brand-saturation) / 1.25) calc(var(--brand-lightness) / 1.25));
--text1-dim: hsl(var(--brand-hue) 15% 75%);
--text2-dim: hsl(var(--brand-hue) 10% 61%);
--surface1-dim: hsl(var(--brand-hue) 10% 20%);
--surface2-dim: hsl(var(--brand-hue) 10% 25%);
--surface3-dim: hsl(var(--brand-hue) 5% 30%);
--surface4-dim: hsl(var(--brand-hue) 5% 35%);
--surface-shadow-dim: var(--brand-hue) 30% 13%;
--shadow-strength-dim: .2;
}
![capture d'écran montrant des couleurs sombres réunies](https://web.dev/static/articles/building/a-color-scheme/image/screenshot-the-dim-color-acb7bb759c10b.png?authuser=5&hl=fr)
Couleurs accessibles
Notez que la luminosité la plus basse pour le jeu de couleurs sombres est de 65% et que la luminosité maximale pour les surfaces sombres est de 25%. Cela représente 40% de lumière qui respire entre les deux. Avec le thème clair, il y a 55% d'espace pour respirer. Conserver les différences de luminosité entre le texte et les couleurs de surface d'environ 40 à 50% peut aider à maintenir des rapports de contraste élevés, tout en constituant un levier subtil d'ajustement si les scores sont mauvais.
Je l'appelle « bump mention til ya pass », c'est-à-dire l'interaction consistant à augmenter la valeur de luminosité jusqu'à ce qu'un outil indique que je passe.
Chacun des thèmes créés dans ce défi passe des scores de contraste. Le jeu de couleurs sombre a le contraste le plus faible, mais il répond quand même aux conditions minimales requises. Pour aider les autres membres de l'équipe à utiliser des couleurs contrastées, il est judicieux de créer un nom de classe qui associe une couleur de surface à une couleur de texte accessible.
.surface1 {
background-color: var(--surface1);
color: var(--text2);
}
.surface2 {
background-color: var(--surface2);
color: var(--text2);
}
.surface3 {
background-color: var(--surface3);
color: var(--text1);
}
.surface4 {
background-color: var(--surface4);
color: var(--text1);
}
![Capture d'écran de l'association de la surface sombre et du texte](https://web.dev/static/articles/building/a-color-scheme/image/screenshot-the-dim-surfa-930653f4c9223.png?authuser=5&hl=fr)
Ombre radicale
Les thèmes utilisent une classe utilitaire appelée .rad-shadow
. Cette ombre a été générée à l'aide de l'outil Smooth Shadow, que j'apprécie beaucoup. J'ai personnalisé l'extrait généré avec mes propres couleurs
et calculs d'opacité. La raison était de créer une ombre que je pourrais
ajuster dans chaque jeu de couleurs.
Pour ce faire, j'ai créé 2 variables pour chaque jeu de couleurs à ajuster : une couleur d'ombre et une intensité de l'ombre. La couleur sert à ajuster la saturation et l'obscurité, tandis que l'intensité est un moyen facile d'augmenter l'intensité de l'ombre lorsqu'il s'agit d'un jeu de couleurs sombres. Le résultat final était quelque chose comme ça.
:root {
--surface-shadow-light: var(--brand-hue) 10% 20%;
--shadow-strength-light: .02;
}
.rad-shadow {
box-shadow:
0 2.8px 2.2px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
0 6.7px 5.3px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .01)),
0 12.5px 10px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
0 22.3px 17.9px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
0 41.8px 33.4px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
0 100px 80px hsl(var(--surface-shadow) / var(--shadow-strength))
;
}
Si je devais aller plus loin avec les ombres dans mon jeu de couleurs, je ferais également que les angles d'ombre soient une constante de la conception, car la direction de la lumière doit être la même entre toutes les ombres de la conception.
Utilisation des jeux de couleurs
Une fois la prédéfinition des couleurs terminée, il est temps de les transformer en propriétés agnostiques des schémas. Ce que je veux dire, c'est qu'en tant qu'auteur CSS dans ce projet de jeu de couleurs, il devrait rarement avoir besoin d'accéder à la valeur d'un jeu de couleurs spécifique. Je veux qu'il soit facile de rester dans le thème.
Pour ce faire, l'utilisation du jeu de couleurs doit être exclusivement effectuée via les propriétés personnalisées génériques, que nous définirons ultérieurement. De cette façon, les utilisateurs qui utilisent les variables de conception n'ont pas à se soucier du jeu de couleurs actuellement défini. Il leur suffit d'utiliser les couleurs de la surface et du texte. Au lieu d'color: var(--text1-light)
, utilisez color: var(--text1)
. L'ensemble des opérations d'adaptation et de pivotement des couleurs se fait à un niveau bien supérieur dans le CSS.
Examinons maintenant les styles de connexion du thème clair dans le bloc de code suivant. Associez une propriété personnalisée générique à la couleur spécifique au thème clair. Désormais, toutes les utilisations de var(--brand)
utiliseront la couleur claire de la marque.
Thème clair (automatique)
:root {
color-scheme: light;
--brand: var(--brand-light);
--text1: var(--text1-light);
--text2: var(--text2-light);
--surface1: var(--surface1-light);
--surface2: var(--surface2-light);
--surface3: var(--surface3-light);
--surface4: var(--surface4-light);
--surface-shadow: var(--surface-shadow-light);
--shadow-strength: var(--shadow-strength-light);
}
Le site utilise désormais le thème clair. C'est un bon moment pour réussir ! Penchons-nous sur d'autres cas de figure, car nous utilisons nos couleurs prédéfinies dans d'autres contextes de jeu de couleurs.
Thème sombre (automatique)
@media (prefers-color-scheme: dark) {
:root {
color-scheme: dark;
--brand: var(--brand-dark);
--text1: var(--text1-dark);
--text2: var(--text2-dark);
--surface1: var(--surface1-dark);
--surface2: var(--surface2-dark);
--surface3: var(--surface3-dark);
--surface4: var(--surface4-dark);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
}
}
Thème clair
[color-scheme="light"] {
color-scheme: light;
--brand: var(--brand-light);
--text1: var(--text1-light);
--text2: var(--text2-light);
--surface1: var(--surface1-light);
--surface2: var(--surface2-light);
--surface3: var(--surface3-light);
--surface4: var(--surface4-light);
--surface-shadow: var(--surface-shadow-light);
--shadow-strength: var(--shadow-strength-light);
}
Thème sombre
[color-scheme="dark"] {
color-scheme: dark;
--brand: var(--brand-dark);
--text1: var(--text1-dark);
--text2: var(--text2-dark);
--surface1: var(--surface1-dark);
--surface2: var(--surface2-dark);
--surface3: var(--surface3-dark);
--surface4: var(--surface4-dark);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
}
Réduire la luminosité du thème
[color-scheme="dim"] {
color-scheme: dark;
--brand: var(--brand-dim);
--text1: var(--text1-dim);
--text2: var(--text2-dim);
--surface1: var(--surface1-dim);
--surface2: var(--surface2-dim);
--surface3: var(--surface3-dim);
--surface4: var(--surface4-dim);
--surface-shadow: var(--surface-shadow-dim);
--shadow-strength: var(--shadow-strength-dim);
}
À ce stade, les auteurs sont libres d'utiliser les jeux de couleurs génériques fournis si nécessaire et n'auront plus à se soucier des thèmes.
Conclusion
Maintenant que tu sais comment j'ai fait, comment tu en ferais ?! 🙂
Diversissons nos approches et apprenons toutes les façons de créer sur le Web. Créez un Codepen ou animez votre propre démo. Envoyez-moi un tweet à mon adresse e-mail pour que je l'ajoute à la section "Remix de la communauté" ci-dessous.
Source
Remix de la communauté
- @chris-kruining a ajouté un curseur de teinte, des couleurs d'état et des modes de contraste pour no-preference
, more
et less
: demo.