2 points par GN⁺ 2025-05-19 | 1 commentaires | Partager sur WhatsApp
  • Avec la fonction contrast-color(), le navigateur choisit automatiquement une couleur de texte noire ou blanche adaptée à différents arrière-plans, notamment pour les boutons
  • Même sur des projets de grande ampleur, il devient plus facile de préserver la lisibilité du texte tout en améliorant l’efficacité de la maintenance
  • Actuellement, Safari Technology Preview utilise l’algorithme officiel de WCAG 2, qui peut toutefois diverger de la perception humaine réelle
  • L’intégration du futur algorithme APCA est en discussion dans le cadre du développement de WCAG 3, avec la promesse d’une meilleure évaluation du contraste de luminosité
  • Au-delà du simple contraste noir/blanc, de nouvelles options de couleur et des fonctions d’amélioration de l’accessibilité devraient être ajoutées à l’avenir

Vue d’ensemble et contexte d’introduction de contrast-color()

  • Dans les designs qui utilisent diverses couleurs d’arrière-plan pour des boutons ou d’autres composants d’interface, la lisibilité de la couleur de police (couleur du texte) est essentielle
  • Jusqu’à présent, les développeurs devaient eux-mêmes associer soigneusement chaque couleur d’arrière-plan à une couleur de texte, mais dans les projets de grande taille cela augmente fortement la complexité de gestion et le risque d’erreurs
  • Avec la fonction CSS contrast-color(), le développeur n’a plus qu’à définir la couleur d’arrière-plan, et le navigateur choisit automatiquement entre du texte noir ou blanc celui qui offre le meilleur contraste
  • Cette approche améliore nettement l’efficacité de la maintenance et du travail de design
  • On peut l’utiliser simplement avec une déclaration comme color: contrast-color(couleur);

Exemple d’utilisation de contrast-color()

  • Il suffit d’affecter la couleur voulue à la variable de fond du bouton, puis contrast-color() choisit automatiquement l’une des deux couleurs contrastées, noir ou blanc, pour le texte
  • Comme une seule couleur doit être gérée à la fois, la maintenance reste simple lors d’un changement de politique de design ou de la prise en charge d’un mode sombre/clair
button {
  background-color: var(--button-color);
  color: contrast-color(var(--button-color));
}
  • En utilisant la Relative Color Syntax, on peut aussi gérer de manière cohérente la couleur de fond et la couleur du texte à l’état hover

Considérations d’accessibilité et explication de l’algorithme

  • L’utilisation de contrast-color() ne résout pas automatiquement tous les problèmes d’accessibilité
  • Pour certaines couleurs d’arrière-plan de luminosité intermédiaire, ni le noir ni le blanc ne peuvent satisfaire les seuils requis
  • L’algorithme WCAG 2 actuellement utilisé dans Safari Technology Preview est la norme officielle d’accessibilité web
    • Cet algorithme effectue son choix sur la base d’un ratio de contraste, mais il peut produire des résultats qui ne correspondent pas au contraste de luminosité réellement perçu à l’œil
  • Par exemple, sur un fond bleu #317CFF, le calcul peut conclure mécaniquement que le noir offre un meilleur contraste, alors qu’en pratique le blanc est plus lisible
  • Face à ces critiques et aux demandes d’amélioration, l’intégration d’APCA (Accessible Perceptual Contrast Algorithm), plus performant, est actuellement discutée dans le cadre du futur standard d’accessibilité WCAG 3
  • APCA calcule le contraste des couleurs en tenant compte des caractéristiques de la perception humaine, ce qui garantit mieux la lisibilité réelle

Assurer un contraste suffisant en conditions réelles

  • La media query CSS @media (prefers-contrast: more) permet d’appliquer des styles à contraste renforcé selon les préférences d’accessibilité de l’utilisateur
@media (prefers-contrast: more) {
  /* Définir des styles avec un contraste plus élevé */
}
  • Par exemple, si la couleur principale de la marque est un vert clair comme #2DAD4E, même si contrast-color() choisit à l’avenir du blanc, le contraste peut encore être insuffisant pour du petit texte
  • En appliquant l’algorithme APCA, on peut s’appuyer plus précisément sur les seuils minimaux requis selon la taille et l’épaisseur de la police, ce qui aide à prendre des décisions de design en pratique
    • Concrètement, pour du texte en 24px avec une graisse de 400, le blanc peut convenir, mais pour une police plus fine ou du texte plus petit, il est recommandé d’utiliser une couleur de fond plus sombre
  • L’équipe design peut gérer facilement via des variables des palettes adaptées à chaque condition, en tenant compte du mode clair/sombre et des préférences prefers-contrast
--button-color: #2DAD4E;

@media (prefers-contrast: more) {
  @media (prefers-color-scheme: light) {
    --button-color: #419543;
  }
  @media (prefers-color-scheme: dark) {
    --button-color: #77CA8B;
  }
}
button {
  background-color: var(--button-color);
  color: contrast-color(var(--button-color));
  font-size: 1.5rem;
  font-weight: 500;
}
  • L’idée essentielle est que, grâce à contrast-color(), il suffit de gérer les couleurs à partir de la couleur d’arrière-plan, tandis que le navigateur génère automatiquement la paire de contraste pour le texte

Au-delà du noir et du blanc

  • La version actuelle de contrast-color() ne choisit qu’entre deux options, noir et blanc, mais les premières versions pouvaient sélectionner parmi plusieurs couleurs
  • Le CSS Working Group privilégie pour l’instant une version simple, limitée au noir et blanc, afin d’assurer la compatibilité avec les évolutions futures de l’algorithme, tout en prévoyant plus tard des extensions comme des options de couleur personnalisées ou la définition d’un seuil de contraste minimal souhaité
  • Même dans sa forme actuelle, la fonction est déjà très utile pour des besoins simples
  • Elle peut être utilisée de multiples façons, non seulement pour les couleurs d’arrière-plan, mais aussi pour les bordures et d’autres éléments visuels

Conclusion et informations de référence

  • Une fois le futur standard d’accessibilité pris en compte, contrast-color() remplacera son algorithme pour offrir une sélection automatique du contraste plus performante
  • D’ici là, la fonction est particulièrement utile lorsque la couleur d’arrière-plan principale est clairement claire ou sombre
  • Elle peut aussi être appliquée largement à différents éléments d’interface, pas seulement au texte
  • Il est souhaitable de continuer à suivre les algorithmes d’accessibilité récents comme APCA (Accessible Perceptual Contrast Algorithm)

Références

  • La documentation officielle d’APCA et l’APCA Contrast Calculator permettent de consulter divers exemples et critères d’évaluation
  • Les discussions de standardisation autour de la fonction contrast-color se poursuivent au sein du CSSWG
  • Il est possible de partager des avis et de participer aux retours via WebKit ou les communautés concernées

1 commentaires

 
GN⁺ 2025-05-19
Commentaire Hacker News
  • Je travaille sur un outil de création de palettes pour résoudre ce problème, afin que les paires de couleurs aient dès la phase de conception des rapports de contraste WCAG/APCA simples et prévisibles. Le site https://www.inclusivecolors.com/ propose davantage de fonctionnalités sur desktop. Une approche consiste à créer des nuanciers par niveaux, de 100 (clair) à 900 (foncé), puis à ajuster la luminosité pour que, par exemple, une couleur de niveau 700 contraste nettement avec le niveau 100, et le niveau 800 avec le niveau 200. Ainsi, on sait que des combinaisons comme red-700 vs gray-100 ou green-800 vs yellow-200 offrent clairement un bon contraste sans avoir à vérifier la luminance. Le menu Contrast permet aussi d’explorer à quel point l’algorithme APCA est plus strict que WCAG, notamment à quel point il est exigeant pour du texte sombre sur fond clair. C’est pour cela qu’il ne faut pas utiliser WCAG pour les thèmes sombres. Dans le menu Examples, si on regarde les palettes Tailwind et IBM Carbon, on voit que chaque niveau varie de façon non linéaire en saturation et en teinte (Hue) : choisir simplement le meilleur contraste entre noir et blanc est facile, mais pour des palettes où le branding est important, le problème est plus complexe et on ne peut pas obtenir les couleurs en ajustant uniquement la luminosité.

  • Il y a un moyen de faire quelque chose de similaire avec lch

     --text: lch(from var(--bg) calc((49.44 - l) * infinity) 0 0);
    

    Source : https://til.jakelazaroff.com/css/…

    • LCH est sympa aussi, mais OKLCH est encore meilleur. https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl/… Cet article a complètement changé ma façon de voir les choses. C’est vraiment un outil incroyable. Étonnamment, aucun de mes amis designers ne connaissait OKLCH. Cette approche résout beaucoup de problèmes.

    • C’est la première fois que je vois une fonction CSS recevoir ses paramètres de cette manière, comme via un callback. Concept vraiment intéressant. Je me demande s’il existe d’autres fonctions de ce style en dehors de lch.

    • Lea Verou a écrit un très bon article sur un contournement similaire. https://lea.verou.me/blog/2024/contrast-color/

  • Cet article offre une excellente vue d’ensemble des avantages et inconvénients de la sélection automatique du contraste. Si vous construisez un site simple, cette méthode fournit facilement et simplement un contraste correct.
    En revanche, si vous avez besoin de conformité WCAG à grande échelle, mieux vaut l’éviter et mettre en place une vraie hiérarchie de tokens de style sémantiques. Les tokens sémantiques accélèrent le développement et peuvent garantir un contraste visuellement plus agréable qu’un simple basculement noir/blanc. L’avantage d’une couche de tokens sémantiques, c’est que la création de thèmes devient très facile, ce qui permet d’ajouter des thèmes clair/sombre à coût quasi nul. Si vos couleurs de marque échouent aux critères WCAG2, vous pouvez aussi créer un thème séparé pour WCAG2/APCA afin d’obtenir la conformité tout en fournissant un meilleur contraste.
    Je m’occupe du flux variables/tokens chez Figma, et j’ai aussi participé aux implémentations du mode sombre chez Figma et Atlassian. Si vous avez des questions sur les tokens, les thèmes ou les couleurs d’accessibilité, n’hésitez pas.

    • Je me demande ce que vous entendez concrètement par tokens sémantiques. C’est pour ce genre de fonctionnalité que j’ai utilisé du CSS-in-JS dans un gros projet, pour les calculs relatifs de couleur et les couleurs de contraste. J’espère que ce type de technique sera largement adopté bientôt.

    • Les deux tiers finaux sont beaucoup trop verbeux, au point d’en devenir pédants. Sur le site ou l’app d’une entreprise, s’appuyer sur ce genre de fonction est risqué parce que la couleur obtenue est imprévisible. WebKit pourrait corriger un bug et changer le résultat des couleurs.

  • J’ai encore du mal à accepter que la couleur de contraste soit déterminée selon l’avis des éditeurs de navigateurs, sans que ce soit toujours juste ni prévisible. Je me demande s’il y aura un critère déterministe garantissant que tous les navigateurs produisent le même résultat. En pratique, cette fonction donne l’impression d’être surtout un outil d’aide à la conception pour l’équipe UX.

    • D’après l’article, le standard précise explicitement la méthode de calcul.

    • Le terme « choisir » me paraît ambigu. En réalité, l’algorithme calcule la couleur.

    • Si on met de côté quelques erreurs ou ambiguïtés dans la formule d’exemple APCA du lien, cela fonctionne de manière 100 % correcte. Pour garantir une cohérence parfaite, quand les deux couleurs candidates (la plus claire et la plus sombre) sont acceptables en même temps, il suffit de se baser sur la luminance du fond (L*) et, par exemple, de choisir la plus claire à partir de L* 60. Là, on obtient une cohérence à 100 %.

  • Quand on travaille sur de gros projets, il est difficile de surveiller séparément le risque que des boutons deviennent illisibles, par exemple sombres avec du texte noir. Mais je me dis qu’on pourrait aussi tout simplement vérifier les boutons un par un avant la mise en production. Sinon, on peut établir et partager une règle d’équipe disant qu’un bouton sombre ne doit jamais avoir de texte noir. La différence entre contraste cognitif et contraste mathématique m’a paru intéressante. Je vais l’intégrer dans mon workflow.

    • En pratique, il est possible de vérifier tous les boutons, mais de cette manière la phase de tests de régression avant livraison peut prendre plusieurs semaines, voire plusieurs mois. Sur un gros projet, il est facile d’avoir plus de mille boutons, et beaucoup n’apparaissent que dans certaines combinaisons d’options ou certains workflows.

    • APCA permet justement de calculer le contraste sur une base perceptive.

  • J’ai connu l’époque où les couleurs système étaient populaires pour styliser les boutons. Le résultat était joli, mais impossible de savoir quel serait le rapport de contraste, donc quelqu’un avait écrit un script JavaScript qui le calculait via getComputedStyle. Si le contraste était mauvais, on utilisait une deuxième couleur candidate ou, en dernier recours, on renforçait le contraste autour du texte avec text-shadow. J’ai oublié la méthode de calcul, mais il me semble qu’on pouvait simplement faire la moyenne des trois valeurs RGB et comparer. Comme la moyenne est plus basse pour le bleu, on pourrait ainsi donner plus souvent la priorité au texte blanc.

  • Ce serait déjà bien qu’on recommande au moins de bonnes couleurs pour les pseudo-classes active, focus, hover, link, visited dans les thèmes clair/sombre. material UI ajoute aussi disabled ainsi que les états before et after.

  • J’avais déjà fait un tutoriel vidéo sur le choix de texte noir/blanc en fonction de la couleur d’arrière-plan. Ma méthode était simple : je convertissais la couleur en niveaux de gris pour décider entre noir et blanc. C’était un travail amusant. Je ne suis pas très bon pour faire des vidéos.
    https://youtu.be/tUJvE4xfTgo?si=vFlegFA_7lzijfSR (attention, c’est en portugais)

    • De façon intéressante, un autre commentaire a justement présenté une formule d’espace colorimétrique qui fait exactement cela.
      https://news.ycombinator.com/item?id=44015990
      La vidéo a l’air correcte aussi. Le code semble bon, mais comme je ne parle pas portugais, je ne peux pas juger le contenu.
  • Si on choisit déjà soi-même toute la palette de couleurs, je me demande pourquoi choisir la couleur du texte de contraste sur un bouton serait plus simple que la choisir directement dès le départ. Cette fonctionnalité ne semble utile que dans un cas très extrême où l’on choisit les couleurs de fond de manière arbitraire sans être capable de choisir aussi la couleur de premier plan, c’est-à-dire la couleur du texte du bouton. Le vrai problème, c’est plutôt le texte sur des images ou sur des fonds très variés, où il faut qu’il reste toujours lisible, et cette fonctionnalité ne traite pas du tout ce cas. Elle ne semble donc aider que dans des situations très limitées, et pour cela on invente même un nouveau verbe, alors que la fonctionnalité se limite à choisir entre noir et blanc, en plus avec ce qui est probablement le pire algorithme de contraste possible (WCAG 2). Impressionnant, vraiment.

    • C’est dommage de balayer un outil simplement parce qu’on n’a jamais eu besoin de l’utiliser soi-même. Beaucoup de sites permettent aux utilisateurs de choisir arbitrairement des couleurs, ou extraient des couleurs depuis des contenus uploadés. Les sites qui prennent l’accessibilité au sérieux doivent donc forcément calculer automatiquement le contraste dans ce genre de cas. Avec une telle fonctionnalité CSS intégrée, même l’accessibilité de base devient facile à mettre en place. Bien sûr, cela ne limite en rien les développeurs qui veulent créer une expérience plus avancée. Ce serait encore mieux si c’était plus personnalisable, comme le package npm contrast-color, mais comme l’explique le billet de blog, l’algorithme qui choisit uniquement noir ou blanc n’est qu’une première étape et des améliorations sont prévues.
      Exemple : https://coolors.co/8fbfe0-7c77b9-1d8a99-0bc9cd-14fff7

    • À propos de la critique sur la faiblesse de l’algorithme de sélection du contraste, il est bien précisé qu’il suit actuellement l’algorithme WCAG 2 et qu’il pourra facilement passer à celui de WCAG 3 une fois celui-ci standardisé.

  • Je me demande s’il existe des alternatives build-time à cette fonctionnalité, applicables à SASS, Tailwind, etc. Il faudra probablement du temps avant une adoption généralisée, et je me demande aussi si l’implémentation sera réellement identique selon les plateformes.