Présentation de base sur l'établissement d'un jeu de couleurs dynamique et configurable
Dans cet article, je souhaite partager des réflexions sur la façon de gérer plusieurs jeux de couleurs en CSS. Tester la fonctionnalité
Si vous préférez regarder une vidéo, voici une version YouTube de cet article:
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 des utilisateurs tout en limitant l'expérience d'écriture. Nous commençons par une couleur de base de la marque et créons un système de variantes: deux couleurs de texte, quatre couleurs de surface et une ombre assortie.
Ce guide commence par définir toutes les couleurs de chaque jeu de couleurs à l'avance. Ils ne sont utilisés pour modifier la page qu'à la toute fin.
La marque
Souvent, une couleur de marque a déjà été définie et est fournie au format hexadécimal ou RGB. Pour ce défi d'interface utilisateur graphique, la couleur de base de la marque 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 permettre un concept d'assombrissement ou d'éclaircissement de la couleur de la marque, par exemple de 20%, les trois canaux de la valeur de couleur hsl doivent être extraits dans leurs propres propriétés personnalisées, comme suit:
* {
--brand-hue: 200;
--brand-saturation: 100%;
--brand-lightness: 50%;
}
Le 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%. Cela est essentiel pour créer un schéma de couleurs, car le CSS peut conserver toutes les couleurs de la même famille de teintes en ajustant les valeurs de saturation et de luminosité hsl.
Thème clair
Chaque variante de couleur sera marquée avec son jeu de couleurs correspondant. Dans ce cas, -light
est ajouté à chaque variante.
Marque
En commençant par la couleur de la marque, elle est recréée en encapsulant les propriétés personnalisées --brand-hue
, --brand-saturation
et --brand-lightness
entre parenthèses 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 nécessitent des 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 avec une luminosité de 10 %, conserve la saturation élevée de 100 % afin que la couleur de la marque puisse toujours transparaître 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 lesquelles ou dans lesquelles le texte se trouve. 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 pour que les gris clairs 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 de couches de papier. Dans ces scénarios, il est préférable de passer de --surface2-light
en survol à --surface3-light
. Un survol entraîne donc une augmentation du contraste (de 99% de luminosité à 92% de luminosité, ce qui le rend plus sombre).
Ombres
Les ombres d'un jeu de couleurs sont au-delà de l'essentiel, mais elles ajoutent une nature réaliste à l'effet et l'aident à se démarquer des ombres basées sur le noir irréalistes. Pour ce faire, la couleur de l'ombre utilisera la propriété personnalisée de teinte, sera légèrement saturée avec la teinte, mais restera très sombre. Créez essentiellement une ombre très sombre 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
sera combinée pour créer une certaine opacité, et le CSS a besoin des éléments pour effectuer des calculs. Pour en savoir plus, passez à la section "Ombre radiale".
Couleurs claires toutes ensemble
Vous n'avez pas besoin de chercher pour savoir 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;
}
Thème sombre
La plupart des marques ne commencent pas par un thème sombre. Il s'agit d'une variante de leur thème principal, généralement plus clair. En revanche, les utilisateurs choisissent souvent un thème sombre pour différents contextes, comme la nuit. Ces facteurs m'ont conduit à garder deux points à l'esprit avec les thèmes sombres:
- Les utilisateurs utiliseront généralement ce thème dans l'obscurité. Testez donc dans l'obscurité.
- Les couleurs doivent être désaturées pour ne pas vibrer à l'écran en raison d'une intensité excessive.
Marque
Le thème clair utilisait les valeurs des trois canaux de couleur hsl de la marque sans les modifier, contrairement au thème sombre. La saturation est réduite de moitié et la luminosité de 50%.
* {
--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 élevées de luminosité, 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 ont une luminosité et une saturation faibles, 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
Dans un thème sombre, les ombres peuvent être très difficiles à voir. Cela a du sens, car il est difficile d'assombrir quelque chose qui est déjà assez sombre. C'est là que --shadow-strength-dark
est 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;
}
Regardez aussi la saturation de cette ombre. Pouvez-vous remarquer la couleur lorsque vous regardez l'interface ? Essayez de supprimer la saturation des outils de développement. Que préférez-vous ?
Couleurs sombres toutes ensemble
* {
--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;
}
Thème sombre
Ce jeu de couleurs repose sur l'orchestration de la luminosité et de la saturation. La saturation doit être suffisante pour que la teinte reste visible, mais elle doit également dépasser de peu les scores de contraste, car elle est destinée à être faible et à faible contraste.
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;
}
Atténuer 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;
}
Couleurs accessibles
Notez que la luminosité la plus faible du jeu de couleurs de texte sombre est de 65% et que la luminosité la plus élevée des surfaces sombres est de 25%. Cela représente 40% d'espace de respiration entre les deux. Dans le thème clair, l'espace de respiration est de 55 %. Maintenir les différences de luminosité entre les couleurs du texte et de la surface autour de 40 à 50% peut aider à maintenir des ratios de contraste des couleurs élevés, tout en étant un levier subtil à ajuster en cas de mauvais scores.
Je l'appelle "bump bump til ya pass", qui correspond à 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 obtient des scores de contraste. Le jeu de couleurs sombre présente le contraste le plus faible, mais il répond tout de même aux exigences minimales. Pour aider les autres membres de l'équipe à utiliser des couleurs contrastantes, il est judicieux de créer une classe de nom 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);
}
Rad Shadow
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 pris l'extrait généré et l'ai personnalisé avec mes propres couleurs et calculs d'opacité. L'objectif était de créer une ombre que je pouvais ajuster dans chaque jeu de couleurs.
Pour ce faire, j'ai créé deux variables pour chaque jeu de couleurs à ajuster : une couleur d'ombre et une intensité d'ombre. La couleur permet d'ajuster la saturation et l'obscurcissement, tandis que l'intensité permet d'augmenter facilement l'intensité des ombres lorsque le jeu de couleurs est sombre. Le résultat final se présentait comme suit.
: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 des angles d'ombre un jeton de conception constant, car la direction de la lumière doit être la même pour 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 indépendantes du schéma. En tant qu'auteur CSS dans ce projet de jeu de couleurs, vous devriez rarement avoir besoin d'accéder à la valeur d'un jeu de couleurs spécifique. Je veux que vous puissiez facilement respecter le thème.
Pour ce faire, l'utilisation du jeu de couleurs doit se faire exclusivement via les propriétés personnalisées génériques, que nous allons définir sous peu. De cette façon, les utilisateurs des variables de conception n'ont jamais à se soucier de la palette de couleurs actuellement définie. Ils doivent simplement utiliser les couleurs de la surface et du texte. Utilisez color: var(--text1)
au lieu de color: var(--text1-light)
. Toutes les adaptations et rotations des couleurs sont effectuées à un niveau beaucoup plus élevé dans le CSS.
En examinant les styles de connexion du thème clair dans le bloc de code suivant, vous pouvez voir qu'ils associent une propriété personnalisée générique à la couleur spécifique du thème clair. Désormais, toutes les utilisations de var(--brand)
utiliseront la couleur de la marque claire.
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 moment très agréable et réussi. Profitons de ces moments pour utiliser 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);
}
Thème sombre
[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 génériques de jeu de couleurs fournis si nécessaire et ne devraient plus jamais avoir à se soucier des thèmes.
Conclusion
Maintenant que vous savez comment j'ai fait, comment pourriez-vous faire ? 🙂
Diversifions nos approches et découvrons toutes les façons de créer sur le Web. Créez un Codepen ou hébergez votre propre démonstration, tweetez-moi avec, et je l'ajouterai à 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
: démo.