Icônes accessibles
La plupart des icônes accompagnent un libellé et doivent se faire oublier des technologies d'assistance ; quelques-unes portent un sens à elles seules et ont besoin d'un nom. glyphfox gère correctement le premier cas par défaut et ramène le second à une seule prop.
Décoratives par défaut
Toute icône glyphfox est rendue avec aria-hidden="true", sauf si vous lui donnez un nom. Les lecteurs d'écran l'ignorent, ce qui est le comportement souhaité pour une icône placée à côté d'un texte visible : le texte indique déjà ce que fait le contrôle, et l'annonce d'une « image » supplémentaire n'est que du bruit.
<!-- <DownloadIcon /> next to a label --> <button type="button"> <svg class="glyphfox glyphfox-download" aria-hidden="true" ...>...</svg> Download </button>
Ce comportement par défaut s'applique partout : composants React, Vue, Svelte et Angular, élément glyph-fox, runtime HTML pur et chaînes produites par toSvg. Vous ne le changez que lorsque le sens repose uniquement sur l'icône.
Icônes porteuses de sens
Passez title et l'icône devient une image dotée d'un nom. Le moteur de rendu ajoute trois choses : un élément <title> en premier enfant, role="img" et aria-label avec le même texte, afin que le nom soit exposé de façon cohérente d'un navigateur et d'un lecteur d'écran à l'autre.
import { CircleCheckIcon, TriangleAlertIcon } from 'glyphfox/react'; export function SyncStatus({ ok }) { return ok ? <CircleCheckIcon title="Synced" color="#15803d" /> : <TriangleAlertIcon title="Sync failed" color="#b91c1c" />; }
<svg class="glyphfox glyphfox-circle-check" role="img" aria-label="Synced" ...> <title>Synced</title> ... </svg>
Dans React, Vue et Svelte, vous pouvez aussi passer aria-label ou aria-labelledby directement au composant. Ils sont appliqués au svg, et l'icône cesse automatiquement d'être décorative, sans l'élément <title> ni son infobulle au survol. decorative prend le pas sur le choix automatique, dans les deux sens : decorative masque une icône même si elle a un titre, decorative={false} l'expose.
Rédigez le nom d'après ce que l'icône signifie à cet endroit, et non d'après ce qu'elle représente. Une icône trash se nomme « Supprimer le brouillon », et non « Poubelle » ; une icône circle check dans une liste de paiements se nomme « Payé ».
Boutons et liens composés uniquement d'une icône
Lorsqu'une icône est le seul contenu d'un bouton ou d'un lien, nommez le contrôle, pas l'icône. C'est le contrôle qui reçoit le focus et que le lecteur d'écran annonce ; l'icône qu'il contient reste décorative.
import { XIcon, SettingsIcon, SearchIcon } from 'glyphfox/react'; export function Toolbar({ onClose }) { return ( <> <button type="button" aria-label="Close dialog" onClick={onClose}> <XIcon /> </button> <a href="/settings" aria-label="Settings"> <SettingsIcon /> </a> <button type="submit"> <SearchIcon /> <span className="visually-hidden">Search the docs</span> </button> </> ); }
Le texte visuellement masqué, troisième technique, est traduit par les outils de traduction des navigateurs, qui ignorent souvent les attributs ; privilégiez-le sur les sites multilingues. Une classe visually-hidden classique réduit l'élément à un seul pixel sans le retirer de l'arbre d'accessibilité.
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
Pour un bouton bascule, c'est l'état qui compte, pas un nouveau nom. Un bouton de menu qui se transforme de menu en x garde son libellé et définit aria-expanded ; un bouton de lecture qui se transforme en pause change de libellé ou utilise aria-pressed. Le morph est la moitié visuelle de ce changement ; le guide des icônes animées montre les deux moitiés ensemble.
État, couleur et contraste
La couleur seule ne doit pas porter le sens (WCAG 1.4.1). Utilisez des formes différentes pour des états différents, comme circle-check, circle-alert et circle-x, et accompagnez-les de texte quand c'est possible. Les badges aident aussi : file+check et file+alert diffèrent par leur forme, pas seulement par leur couleur.
Les icônes nécessaires pour comprendre la page ou pour trouver un contrôle doivent atteindre un rapport de contraste de 3 pour 1 avec leur arrière-plan (WCAG 1.4.11, contraste du contenu non textuel). Mesurez la couleur du trait, car c'est lui qui dessine la forme ; la couche duotone translucide n'est qu'une décoration par-dessus. Les icônes décoratives placées à côté d'un texte ne sont pas concernées par cette règle, mais un contraste faible les rend tout de même plus difficiles à repérer d'un coup d'œil.
Les traits fins paraissent plus clairs que leur couleur ne le laisse penser, car l'anticrénelage les mélange à l'arrière-plan. En dessous de 24 pixels, glyphfox compense en épaississant le trait jusqu'à 30 % ; à 14 ou 16 pixels sur une couleur atténuée, un weight de 2,25 ou 2,5 garde les icônes lisibles. absoluteWeight désactive cette compensation : utilisez-le donc avec précaution aux petites tailles.
Mouvement
Chaque état vivant et chaque morph respecte prefers-reduced-motion: reduce : les presets ne sont pas joués, les morphs CSS basculent sans transition et les morphs des composants passent directement à leur forme finale. L'état final reste visible : aucune information n'est donc perdue.
Un contenu qui bouge de lui-même pendant plus de cinq secondes doit pouvoir être mis en pause (WCAG 2.2.2). Liez les animations en boucle comme spin au processus qu'elles illustrent et arrêtez-les lorsqu'il se termine, et évitez les animations en boucle destinées à attirer l'attention, comme une cloche qui tremble indéfiniment.
Mises en page de droite à gauche
Dans les interfaces en arabe, en hébreu ou en persan, les icônes orientées dans le sens de lecture doivent être retournées : flèches précédent et suivant, chevrons des fils d'Ariane, répondre et annuler. mirrorRtl ajoute une classe qui inverse l'icône en miroir dès qu'elle se trouve dans dir="rtl" : le même balisage fonctionne ainsi dans les deux sens.
import { ChevronLeftIcon, ChevronRightIcon } from 'glyphfox/react'; export function Pager({ onPrev, onNext }) { return ( <nav aria-label="Pagination"> <button type="button" onClick={onPrev}><ChevronLeftIcon mirrorRtl /> Previous</button> <button type="button" onClick={onNext}>Next <ChevronRightIcon mirrorRtl /></button> </nav> ); }
N'inversez pas les icônes dont l'orientation ne suit pas le texte : les commandes multimédias comme play et fast-forward continuent de pointer vers la droite, l'icône clock tourne toujours dans le sens des aiguilles d'une montre, check reste tel quel, et rotate-cw signifie toujours le sens horaire.
Masques, sprites, l'élément et Angular
- Les classes Tailwind CSS rendent un élément vide avec un masque, qui n'a aucune sémantique. Ajoutez
aria-hidden="true"et donnez au contrôle un libellé visuellement masqué. En mode Contraste élevé de Windows, une icône en masque peut disparaître ; le guide Tailwind CSS explique comment y remédier. - Les sprites SVG vous laissent gérer le
svgextérieur : ajoutezaria-hidden="true"pour une icône décorative, ourole="img"etaria-labelpour une icône porteuse de sens. Le guide des sprites contient des exemples. - L'élément
glyph-foxet le composant Angulargf-iconrendent lesvgà l'intérieur de l'élément hôte. Unaria-labelsur l'hôte fait dusvginterne une image, mais ne lui donne pas de nom, et un libellé placé sur un élément générique n'est pas annoncé de façon fiable. Utilisez l'attribut ou l'inputtitle, qui nomme lesvginterne.
<!-- names the inner svg: role img, aria-label and a title --> <glyph-fox name="circle-alert" title="Payment failed"></glyph-fox> <!-- Angular --> <gf-icon name="circle-alert" title="Payment failed"></gf-icon>
Tester
- Ouvrez l'arbre d'accessibilité dans les outils de développement de votre navigateur et sélectionnez le contrôle : son nom doit correspondre au libellé que vous avez écrit, et les icônes décoratives ne doivent pas apparaître du tout.
- Naviguez avec un lecteur d'écran : VoiceOver sur macOS et iOS, NVDA sur Windows, TalkBack sur Android. Repérez les noms annoncés deux fois et tout ce qui est annoncé simplement comme « image ».
- Émulez
prefers-reduced-motionetforced-colorsdans le panneau Rendu des outils de développement de Chromium, puis vérifiez que les icônes restent visibles et immobiles. - Vérifiez le contraste des icônes porteuses de sens avec une pipette, par rapport à l'arrière-plan réel, y compris dans les états de survol et de focus.
Les props utiles ici
| Prop | Type | Par défaut | Description |
|---|---|---|---|
color | string | currentColor | Couleur principale. |
weight | number | 2 | Trait de 1 à 3 sur la grille de 24, avec compensation optique en dessous de 24 px. |
absoluteWeight | boolean | false | Garde le trait à weight pixels quelle que soit la taille. |
mirrorRtl | boolean | false | Miroir dans les mises en page de droite à gauche. |
title | string | aucun | Nom accessible : title, role img et aria-label. |
decorative | boolean | true sans title | Masque l'icône aux technologies d'assistance. |
Pièges courants
- Nommer à la fois le contrôle et l'icône
- Un
titlesur une icône placée dans un bouton qui a déjà un libellé pousse les lecteurs d'écran à annoncer les deux, et le<title>s'affiche en plus sous forme d'infobulle au survol. Ne nommez qu'une chose : le contrôle. - Une image sans nom
decorative={false}sanstitleniaria-labelexpose une image sans nom, que les lecteurs d'écran annoncent comme « image » ou par son nom de fichier. Donnez un nom à chaque icône exposée.- Un état que seule l'icône montre
- Un morph de
copyverscheckest invisible pour un lecteur d'écran. Annoncez le résultat sous forme de texte : changez le libellé du bouton, ou placez « Copié » dans une région live avecrole="status". - Infobulles issues des titres
- L'infobulle que le navigateur affiche à partir de
<title>n'apparaît qu'au survol de la souris, jamais au focus ni au toucher. N'y placez aucune information qui ne soit pas disponible autrement. - Libellés sur l'élément hôte
- Sur
glyph-foxetgf-icon, utiliseztitleplutôt qu'aria-label, comme décrit plus haut.
Questions fréquentes
Chaque icône doit-elle avoir un titre ?
Non. La plupart des icônes se trouvent à côté d'un texte ou dans un contrôle doté d'un libellé, et un titre n'y ajoute que du bruit. Donnez un titre aux icônes isolées qui transmettent une information, comme une icône d'état dans une cellule de tableau.
L'attribut aria-hidden suffit-il pour les icônes décoratives ?
Oui. aria-hidden="true", que glyphfox ajoute par défaut, retire l'icône de l'arbre d'accessibilité. Les icônes SVG ne peuvent pas recevoir le focus : il n'y a donc rien d'autre à masquer.