Science des couleurs pour les designers d'interfaces : ce que j'ai appris en créant un site sans couleur
Les Directives pour l’accessibilité des contenus Web (WCAG) du W3C exigent un rapport de contraste minimum de 4,5:1 pour le texte normal, pourtant une enquête WebAIM de 2023 a révélé que 83,6 % des un million de sites les plus visités présentaient des défaillances de contraste WCAG 2 détectables sur leurs pages d’accueil. J’ai conçu blakecrosley.com avec le problème inverse : un contraste maximum (21:1) partout, puis une réduction sélective.1
TL;DR
J’ai conçu mon site personnel sans aucune couleur de marque. L’ensemble de la hiérarchie visuelle fonctionne grâce à du texte blanc sur noir absolu (#000000) réparti sur quatre niveaux d’opacité : 100 %, 65 %, 40 % et 10 %. Cette décision m’a contraint à apprendre la science perceptuelle des couleurs — pourquoi sRGB ment sur l’espacement uniforme, comment OKLCH résout ce problème, et pourquoi le mode sombre nécessite des relations de contraste différentes du mode clair. Les outils interactifs ci-dessous vous permettent d’explorer les rapports de contraste et les différences entre espaces colorimétriques. La conclusion : comprendre la science derrière la perception des couleurs produit de meilleures décisions de design que l’intuition esthétique.
Ma non-palette de couleurs
La plupart des systèmes de design commencent par une palette de couleurs. Le mien commence par l’absence de palette :
:root {
--color-bg-dark: #000000;
--color-bg-elevated: #111111;
--color-bg-surface: #1a1a1a;
--color-text-primary: #ffffff;
--color-text-secondary: rgba(255,255,255,0.65);
--color-text-tertiary: rgba(255,255,255,0.4);
--color-border: rgba(255,255,255,0.1);
--color-border-subtle: rgba(255,255,255,0.05);
--color-accent: #ffffff;
}
Dix tokens. Aucune couleur de marque. Aucune palette sémantique erreur/succès/avertissement. L’ensemble de la hiérarchie visuelle fonctionne grâce à quatre niveaux de transparence.2
Pourquoi quatre niveaux suffisent
Chaque niveau remplit une fonction de communication spécifique :
| Niveau | Opacité | Token CSS | Fonction | Ratio WCAG (sur #000) |
|---|---|---|---|---|
| Primaire | 100 % | --color-text-primary |
Titres, corps de texte, contenu essentiel | 21:1 (AAA) |
| Secondaire | 65 % | --color-text-secondary |
Sous-titres, navigation, métadonnées | 13,7:1 (AAA) |
| Tertiaire | 40 % | --color-text-tertiary |
Horodatages, texte d’aide, états désactivés | 8,4:1 (AAA) |
| Structurel | 10 % | --color-border |
Bordures, séparateurs, séparation d’arrière-plan | N/A (non-texte) |
Chaque niveau satisfait le critère WCAG AAA (7:1) pour le contraste du texte. Le niveau tertiaire à 40 % d’opacité produit un ratio de 8,4:1 — presque le double du minimum AA de 4,5:1. Le choix brutaliste du noir absolu (#000000 plutôt que #0a0a0a ou #1a1a1a) offre à chaque niveau de texte une marge de contraste maximale.3
L’incident --spacing-2xs
J’ai découvert la valeur de tokens de design stricts lorsque j’ai utilisé --spacing-2xs pour la marge d’un sous-titre. Ce token n’existait pas dans ma définition :root. Le CSS a échoué silencieusement, la mise en page s’est cassée, et j’ai passé 20 minutes à déboguer un problème d’espacement qui aurait dû être une erreur à la compilation. La correction : passer à --spacing-xs (le plus petit token que j’avais défini). La leçon : si une valeur n’existe pas dans le système, c’est le design qui est faux, pas le système.4
Pourquoi sRGB ment aux designers
Le problème de la non-uniformité perceptuelle
sRGB (l’espace colorimétrique standard du web) projette les couleurs dans un cube où chaque axe (rouge, vert, bleu) va de 0 à 255. Un déplacement de 50 unités dans le canal rouge ne produit pas le même changement perçu qu’un déplacement de 50 unités dans le canal vert. L’œil humain contient davantage de cônes sensibles au vert qu’au rouge ou au bleu, ce qui rend les variations de vert plus perceptibles que des variations équivalentes de rouge.5
La conséquence pratique : un designer qui crée une palette de couleurs en espaçant uniformément les valeurs hexadécimales produit des couleurs qui paraissent inégalement espacées. Le gris « moyen » entre #000000 et #FFFFFF n’est pas #808080 (point médian mathématique) mais approximativement #777777 (point médian perceptuel), car la perception humaine de la luminosité suit une loi de puissance plutôt qu’une fonction linéaire.6
Mon site contourne entièrement le problème. En utilisant uniquement du blanc à différentes opacités, j’évite le piège de l’uniformité sRGB. L’opacité évolue linéairement avec la transparence perçue sur un fond noir — une propriété que le mélange de couleurs sRGB ne partage pas.
La solution OKLCH
OKLCH (Oklab Lightness, Chroma, Hue) est un espace colorimétrique perceptuellement uniforme où des distances mathématiques égales correspondent à des différences perçues égales. Un pas de 10 unités en luminosité apparaît toujours comme le même degré de changement, quelle que soit la couleur de départ.7
/* sRGB: mathematically even, perceptually uneven */
--gray-100: #f5f5f5;
--gray-200: #e5e5e5;
--gray-300: #d4d4d4;
/* OKLCH: perceptually even steps */
--gray-100: oklch(96% 0 0);
--gray-200: oklch(88% 0 0);
--gray-300: oklch(80% 0 0);
Le CSS moderne prend en charge oklch() nativement. Pour mon prochain projet nécessitant une palette de couleurs, je définirai la palette en OKLCH. Pour mon site actuel, le système basé sur l’opacité atteint la même uniformité perceptuelle par d’autres moyens.
Ma décision pour le mode sombre : pas de mode clair
Mon site n’a pas de media query prefers-color-scheme. Il fonctionne exclusivement en mode sombre. La décision était délibérée.8
L’argument en faveur des deux modes : Les utilisateurs s’attendent à une option de mode clair. L’intégration des préférences système respecte le choix de l’utilisateur.
L’argument contre (que j’ai choisi) : Maintenir deux systèmes visuels compromet inévitablement les deux. Un design qui fonctionne à 65 % d’opacité sur noir nécessite une opacité différente sur blanc (plus proche de 45 %) pour obtenir le même poids perceptuel. Chaque état d’interaction, chaque bordure, chaque ombre nécessite un recalibrage. J’ai choisi de bien concevoir un seul système plutôt que deux systèmes passables.
L’arrière-plan noir absolu (#000000) maximise le contraste disponible pour chaque niveau de texte :
/* My actual typography contrast hierarchy */
.hero__title { color: var(--color-text-primary); } /* 21:1 */
.hero__subtitle { color: var(--color-text-secondary); } /* 13.7:1 */
.nav a { color: var(--color-text-secondary); } /* 13.7:1 */
.nav a:hover { color: var(--color-text-primary); } /* 21:1 */
La transition au survol (secondaire → primaire) fournit un retour fonctionnel uniquement par le changement de contraste — aucun changement de couleur n’est nécessaire.
Contraste et lisibilité
Exigences de contraste WCAG
| Niveau | Texte normal (< 18pt) | Grand texte (≥ 18pt ou 14pt gras) |
|---|---|---|
| AA | 4,5:1 | 3:1 |
| AAA | 7:1 | 4,5:1 |
Le rapport de contraste mesure la différence de luminance relative entre les couleurs de premier plan et d’arrière-plan. Un ratio de 1:1 signifie aucun contraste (couleurs identiques). Un ratio de 21:1 signifie un contraste maximum (noir sur blanc ou blanc sur noir).9
Au-delà du WCAG : APCA
L’algorithme de contraste WCAG 2 présente des limites connues. L’algorithme traite toutes les couleurs de manière identique quelle que soit la polarité (sombre sur clair vs. clair sur sombre), bien que la recherche montre que la perception humaine du contraste diffère significativement entre les deux modes.10
APCA (Accessible Perceptual Contrast Algorithm) corrige ces limites en tenant compte de : - La sensibilité à la polarité : Le texte sombre sur fond clair est plus lisible que le texte clair sur fond sombre au même rapport de contraste mathématique - La fréquence spatiale : Les polices fines nécessitent plus de contraste que les polices grasses à la même taille - L’adaptation : L’œil s’adapte à la luminance environnante de la page, ce qui affecte le contraste perçu
APCA devrait constituer la base des exigences de contraste WCAG 3.0. Mon site bénéficie de l’observation sur la polarité : puisque j’utilise exclusivement du clair sur sombre, j’ai besoin de ratios de contraste plus élevés qu’un site en mode clair. Mon niveau de texte le plus bas (40 % d’opacité, ratio de 8,4:1) dépasse même le minimum recommandé par APCA pour le corps de texte sur fond sombre.
Couleur sémantique sans couleur
Les systèmes de couleurs en production attribuent généralement des couleurs aux fonctions (vert pour le succès, rouge pour l’erreur). Mon site évite entièrement la couleur fonctionnelle car il ne comporte aucune interface transactionnelle — pas de formulaires, pas de messages de statut, pas d’états succès/erreur. Le contenu est statique.
Si j’avais besoin de couleur sémantique, je l’ajouterais de manière chirurgicale :
| Fonction | Approche classique | Mon approche hypothétique |
|---|---|---|
| Succès | Vert | Texte blanc + icône de coche |
| Erreur | Rouge | Texte blanc + icône X + bordure accentuée |
| Avertissement | Ambre | Texte blanc + icône d’exclamation |
Associer des icônes au texte élimine la communication uniquement par la couleur, qui échoue pour les environ 8 % d’hommes présentant une déficience de la vision des couleurs. Cette approche préserve également mon système monochrome. La couleur servirait d’accent, pas d’élément structurel.11
La hiérarchie typographique d’abord
Sans couleur pour porter la hiérarchie, la typographie porte tout sur mon site :
:root {
--font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text",
"SF Pro Display", "Helvetica Neue", Arial, sans-serif;
--font-size-display: 5rem; /* 80px — hero headlines */
--font-size-7xl: 3.875rem; /* 62px */
--font-size-base: 1rem; /* 16px — body text */
--font-size-xs: 0.75rem; /* 12px — metadata */
}
Des polices système, pas de polices web personnalisées. Ce choix est à la fois une décision brutaliste (utiliser le matériau natif de la plateforme) et une décision de performance (zéro latence de chargement de polices, contribuant aux scores Lighthouse de 100/100). La taille d’affichage (80px) avec un espacement des lettres serré (-0.03em) donne aux titres de la gravité sans décoration. Le corps de texte à 16px avec une hauteur de ligne généreuse (1.7) privilégie la lisibilité plutôt que la densité.12
L’échelle typographique en 13 étapes, de 0.75rem à 5rem, offre suffisamment de granularité pour exprimer la hiérarchie uniquement par la taille. Combinée avec les quatre niveaux d’opacité, j’obtiens 52 combinaisons possibles (13 tailles × 4 opacités) — largement suffisant pour exprimer n’importe quelle hiérarchie de contenu sans recourir à la couleur.
Points clés à retenir
Pour les designers : - Définissez vos palettes de couleurs en OKLCH plutôt qu’en sRGB ; les espaces colorimétriques perceptuellement uniformes produisent une hiérarchie prévisible et des ratios de contraste cohérents sur l’ensemble de la palette - Testez votre niveau de texte tertiaire selon le critère WCAG AAA (7:1), pas uniquement AA (4,5:1) ; le seuil AAA offre suffisamment de marge pour les conditions réelles d’écran (faible luminosité, reflets, écrans vieillissants) - Demandez-vous si votre projet a réellement besoin de couleur ; mon site prouve que la typographie et l’opacité seules peuvent porter une hiérarchie visuelle complète
Pour les développeurs :
- Utilisez oklch() en CSS pour les définitions de couleur et testez les ratios de contraste avec WCAG 2 (standard actuel) et APCA (standard à venir) ; la prise en charge de oklch() par les navigateurs est disponible dans tous les navigateurs modernes
- Implémentez le mode sombre en ajustant la luminosité et la saturation dans l’espace OKLCH plutôt qu’en inversant les valeurs hexadécimales ; l’ajustement perceptuel produit de meilleurs résultats que l’inversion mathématique
- L’application stricte des tokens de design prévient les échecs CSS silencieux ; si un token n’existe pas, c’est le design qui doit changer, pas le système de tokens
Références
-
WebAIM, « The WebAIM Million: 2023 Accessibility Analysis », 2023. ↩
-
Propriétés CSS personnalisées de l’auteur, issues de
critical.css. 10 tokens de couleur, tous dérivés de relations d’opacité blanc sur noir. ↩ -
Calculs de contraste WCAG de l’auteur. Primaire (21:1), secondaire (13,7:1), tertiaire (8,4:1), tous supérieurs au minimum AAA de 7:1. ↩
-
Expérience de débogage de l’auteur.
--spacing-2xsétait utilisé mais jamais défini dans:root. Documenté dans les entrées d’erreurs de MEMORY.md. ↩ -
Hunt, R.W.G., The Reproduction of Colour, Wiley, 2004. ↩
-
Poynton, Charles, Digital Video and HD, Morgan Kaufmann, 2012. Correction gamma et linéarité perceptuelle. ↩
-
Ottosson, Bjorn, « A perceptual color space for image processing », 2020. Spécification OKLCH. ↩
-
Décision de design de l’auteur. Un mode sombre unique évite le compromis visuel inhérent au maintien de systèmes clair/sombre parallèles. ↩
-
W3C, « Web Content Accessibility Guidelines (WCAG) 2.1 », 2018. ↩
-
Somers, Andrew, « APCA Contrast Calculator », 2023. ↩
-
W3C, « WCAG 2.1 Success Criterion 1.4.1: Use of Color », 2018. ↩
-
Système typographique de l’auteur. Échelle de polices en 13 étapes de 0.75rem (12px) à 5rem (80px). La pile de polices système élimine les problèmes FOIT/FOUT. ↩