Chapitre 8.2 — SVG & icônes
⏱️ TL;DR — Un
<svg>n’est pas une<img>: il n’a pas d’attributalt. Pour le rendre accessible, on distingue deux cas. Informatif (il porte du sens) →role="img"+ un nom via<title>ouaria-label. Décoratif (pur ornement) →aria-hidden="true"etfocusable="false"pour le retirer de l’arbre d’accessibilité. Cas le plus fréquent et le plus raté : une icône seule dans un bouton (icon-only). Sans texte visible, ce bouton doit recevoir un nom accessible, sinon le lecteur d’écran annonce « bouton » tout court — inutilisable.
🎯 Objectifs
- Rendre un SVG informatif accessible avec
role="img"+<title>ouaria-label. - Neutraliser un SVG décoratif avec
aria-hidden="true"etfocusable="false". - Donner un nom accessible à une icône seule dans un bouton ou un lien.
- Éviter les pièges des icon fonts (icônes en police de caractères).
Le SVG n’a pas de alt
L’attribut alt n’existe que sur <img>. Un SVG inline (<svg>…</svg> directement dans le HTML) est un arbre d’éléments graphiques : par défaut, son accessibilité est incohérente d’un lecteur d’écran à l’autre. On la rend explicite. Deux questions, comme pour les images : ce SVG porte-t-il une information, ou est-il décoratif ?
SVG informatif
Il transmet du sens (un pictogramme qui remplace du texte, un logo, un schéma simple). On lui donne :
role="img": on annonce à l’arbre d’accessibilité « ceci est une image » (et on masque sa structure interne).- un nom accessible : soit un
<title>en premier enfant du SVG, soitaria-labelsur le<svg>.
<!-- ✅ SVG informatif avec <title> -->
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>Cours terminé</title>
<path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z" />
</svg>
<!-- ✅ Équivalent avec aria-label -->
<svg role="img" aria-label="Cours terminé" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z" />
</svg>En JSX/React, <title> fonctionne pareil ; pense juste à lier un id si tu utilises aria-labelledby.
// ✅ SVG informatif en React
function IconValide() {
return (
<svg role="img" aria-labelledby="t-valide" viewBox="0 0 24 24">
<title id="t-valide">Cours terminé</title>
<path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z" />
</svg>
);
}SVG décoratif
Il n’ajoute rien à ce qui est déjà écrit (une icône posée à côté d’un mot qui dit déjà la même chose, un ornement). On le sort de l’arbre d’accessibilité :
aria-hidden="true": le lecteur d’écran l’ignore totalement.focusable="false": évite qu’en Internet Explorer / vieux navigateurs le SVG capte le focus au clavier (piège historique).
<!-- ✅ Icône décorative à côté d'un texte qui dit déjà tout -->
<a href="/telecharger">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24"><path d="M12 3v12m0 0-4-4m4 4 4-4M5 21h14" /></svg>
Télécharger le support
</a>Ici le lien dit déjà « Télécharger le support » : l’icône flèche est un doublon visuel, on la masque. Le lecteur d’écran annonce « Télécharger le support, lien » — parfait.
Le cas critique : l’icône seule (icon-only)
Un bouton ou un lien qui ne contient qu’une icône, sans aucun texte visible, est le piège n°1 des interfaces modernes. Sans nom accessible, le lecteur d’écran n’a rien à annoncer : « bouton ». L’utilisateur ne sait pas ce qu’il fait.
La règle est absolue : une icône seule dans un contrôle DOIT avoir un nom accessible. Deux techniques.
<!-- ❌ Rien à annoncer : « bouton », sans plus -->
<button>
<svg viewBox="0 0 24 24"><path d="M15.5 14h-.8l-.3-.3a6.5 6.5 0 1 0-.7.7l.3.3v.8l5 5 1.5-1.5-5-5zM10 14a4 4 0 1 1 0-8 4 4 0 0 1 0 8z" /></svg>
</button>
<!-- ✅ Nom sur le bouton via aria-label + icône masquée -->
<button aria-label="Rechercher">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24"><path d="M15.5 14h-.8l-.3-.3a6.5 6.5 0 1 0-.7.7l.3.3v.8l5 5 1.5-1.5-5-5zM10 14a4 4 0 1 1 0-8 4 4 0 0 1 0 8z" /></svg>
</button>
<!-- ✅ Variante : texte masqué visuellement (visually-hidden), lu par le lecteur d'écran -->
<button>
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24"><path d="M15.5 14h-.8l-.3-.3a6.5 6.5 0 1 0-.7.7l.3.3v.8l5 5 1.5-1.5-5-5zM10 14a4 4 0 1 1 0-8 4 4 0 0 1 0 8z" /></svg>
<span class="visually-hidden">Rechercher</span>
</button>Deux approches équivalentes : aria-label sur le contrôle (avec l’icône en aria-hidden), ou un <span class="visually-hidden"> avec un vrai texte. La seconde a un avantage : le texte survit si le CSS ou la traduction automatique casse aria-label. Dans les deux cas, l’icône est masquée pour ne pas parasiter le nom.
⚠️ Piège — Le bouton icône muet est partout : menu burger, fermeture de modale (la croix
×), like, partage, corbeille. Chacun sans nom accessible devient un « bouton » anonyme pour le lecteur d’écran. Passe ton interface en revue : tout contrôle qui n’a pas de texte visible doit avoir unaria-labelou un texte masqué. C’est le défaut le plus fréquent des audits de composants.
Les icon fonts, un cas piégeux
Certaines libs affichent les icônes via une police de caractères (<i class="fa fa-trash"></i>) : le glyphe est en réalité un caractère. Problèmes : selon le lecteur d’écran, ce caractère peut être lu à voix haute (un symbole aléatoire), ou ignoré. Toujours :
- masquer le glyphe :
aria-hidden="true"sur l’élément<i>porteur ; - donner le nom sur le contrôle (
aria-label) ou via un texte masqué.
<!-- ✅ Icon font neutralisée + nom accessible -->
<button aria-label="Supprimer">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>Quand tu peux choisir, préfère des SVG inline aux icon fonts : plus nets, plus contrôlables, et l’accessibilité y est explicite.
♿ Côté utilisateur — Sur une barre d’outils de six boutons icônes sans nom, un utilisateur de lecteur d’écran entend « bouton, bouton, bouton, bouton, bouton, bouton ». Il ne peut ni les distinguer ni deviner lequel supprime, lequel partage. Avec des noms : « Modifier, bouton », « Partager, bouton », « Supprimer, bouton »… La barre redevient utilisable. Une icône, c’est du sens visuel ; le nom accessible en est la traduction.
🧭 Sur A11yLearn — La barre d’actions d’une leçon (marquer comme lue, mettre en favori, partager, signaler) n’affiche que des icônes SVG pour rester compacte. On a systématisé : chaque
<button>porte unaria-labelexplicite (« Marquer comme lue », « Ajouter aux favoris »…) et chaque<svg>interne est enaria-hidden="true" focusable="false". Un lint maison refuse en CI tout<button>sans texte niaria-label: impossible d’introduire un bouton icône muet.
✏️ Exercices
Exercice 1 — Informatif ou décoratif ? Pour chaque SVG, dis comment le rendre accessible : (a) une icône « cadenas » seule dans un bouton « verrouiller le cours », (b) une petite étoile posée juste avant le mot visible « Favori », (c) un pictogramme d’avertissement qui remplace le mot « Attention » (aucun texte à côté).
✅ Solution
(a) Fonctionnelle/informative, icône seule → nom sur le bouton : aria-label="Verrouiller le cours", SVG en aria-hidden="true" focusable="false". (b) Décorative (le mot « Favori » est déjà là) → aria-hidden="true" focusable="false". (c) Informative (elle remplace un mot) → role="img" + <title>Attention</title> ou aria-label="Attention".
Exercice 2 — Corrige le bouton de fermeture. Ce bouton ferme une modale. Rends-le accessible.
<button onclick="closeModal()">
<svg viewBox="0 0 24 24"><path d="M6 6l12 12M18 6L6 18" /></svg>
</button>✅ Solution
L’icône croix est seule : le bouton n’a aucun nom. On ajoute un nom accessible et on masque l’icône.
<button onclick="closeModal()" aria-label="Fermer">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24"><path d="M6 6l12 12M18 6L6 18" /></svg>
</button>Le lecteur d’écran annonce alors « Fermer, bouton ».
🧠 Quiz de révision
1. Pourquoi un <svg> ne se traite-t-il pas comme une <img> ?
<svg> ne se traite-t-il pas comme une <img> ?Parce qu’un SVG inline n’a pas d’attribut alt et que, par défaut, son accessibilité varie d’un lecteur d’écran à l’autre. On l’explicite : role="img" + <title>/aria-label s’il est informatif, ou aria-hidden="true" + focusable="false" s’il est décoratif.
2. Comment nommer un SVG informatif ?
Avec role="img" sur le <svg>, puis un nom accessible : soit un <title> en premier enfant (éventuellement lié par aria-labelledby), soit aria-label directement sur le <svg>.
3. Que mettre sur un SVG purement décoratif ?
aria-hidden="true" pour le retirer de l’arbre d’accessibilité, et focusable="false" pour éviter qu’il capte le focus au clavier dans certains navigateurs. Le lecteur d’écran l’ignore alors totalement.
4. Un bouton ne contient qu’une icône. Quelle est la règle ?
Il doit avoir un nom accessible, sinon le lecteur d’écran annonce « bouton » sans plus. On met un aria-label sur le bouton (avec l’icône en aria-hidden), ou un texte masqué (visually-hidden) à l’intérieur.
5. Quel est le risque avec une icon font ?
Le glyphe est un caractère : selon le lecteur d’écran, il peut être lu à voix haute (symbole incompréhensible) ou ignoré. On masque toujours le porteur (aria-hidden="true") et on donne le nom sur le contrôle. Les SVG inline sont préférables quand on a le choix.
Chapitre suivant : Images complexes — décrire graphiques, schémas et cartes par une description longue ou un tableau.