Une icône sans texte visible, c’est une image. Et toute image soumise à l’auditeur RGAA suit les mêmes règles : elle est décorative ou elle porte une information. Si elle porte une information et qu’aucune alternative n’est fournie, le critère 1.1 est non conforme. Si elle est dans un lien ou un bouton sans intitulé, le critère 6.2 tombe également.
Le sujet est simple en théorie. En pratique, trois technologies coexistent sur le web (images classiques, SVG, font-icons), et chacune a ses spécificités.
La question à poser en premier
Avant de choisir un attribut, une seule question : est-ce que supprimer cette icône entraîne une perte d’information ?
Si l’icône est dans un bouton qui a déjà un texte lisible (“Envoyer”), la supprimer ne retire rien : elle est décorative. Si elle est dans un bouton sans autre texte, la supprimer rend le bouton incompréhensible : elle est informative, ou plus exactement c’est le bouton qui ne porte pas son nom.
Cette distinction commande tout ce qui suit.
Icône décorative
Une icône est décorative quand le texte adjacent dit déjà ce qu’elle représente. L’icône enveloppe à côté du mot “Contact”, l’icône maison à côté du mot “Accueil” : leur suppression ne retire aucune information.
Pour une <img>, l’attribut alt="" (vide, pas absent) le signale :
<!-- ✅ Décorative : alt vide -->
<img src="icone-enveloppe.svg" alt="" aria-hidden="true">
<span>Contact</span>
Pour un SVG inline, aria-hidden="true" sur l’élément <svg> :
<!-- ✅ SVG décoratif -->
<svg aria-hidden="true" focusable="false" width="20" height="20">
<use href="#icon-enveloppe"/>
</svg>
<span>Contact</span>
L’attribut focusable="false" sur le SVG n’est pas cosmétique : Internet Explorer et certaines versions d’Edge anciens rendaient les SVG inline focusables par défaut. Sur les navigateurs modernes, c’est sans effet, mais sa présence évite les surprises.
Pour une font-icon (Font Awesome, Material Icons) :
<!-- ✅ Font-icon décorative -->
<i class="fa fa-envelope" aria-hidden="true"></i>
<span>Contact</span>
Sans aria-hidden="true", le lecteur d’écran annonce le contenu textuel généré de l’élément <i> : souvent rien, parfois le caractère Unicode de l’icône, qui s’entend comme un code incompréhensible ou un nom de caractère.
Icône informative seule
Une icône est informative seule quand elle n’est pas dans un élément interactif et qu’aucun texte adjacent ne transmet la même information. Un pictogramme de statut, une icône d’alerte, un indicateur de type de fichier : ces cas existent, mais ils sont rares sur un site institutionnel standard.
Pour une <img> :
<!-- ✅ Image informative : alt décrit l'information, pas l'apparence -->
<img src="icone-alerte.svg" alt="Attention : service fermé ce jour">
Pour un SVG inline, deux méthodes. La plus robuste associe un élément <title> à l’intérieur du SVG et pointe dessus via aria-labelledby :
<!-- ✅ SVG informatif : title + aria-labelledby -->
<svg role="img" aria-labelledby="titre-alerte" width="20" height="20">
<title id="titre-alerte">Attention : service fermé ce jour</title>
<use href="#icon-alerte"/>
</svg>
La méthode avec aria-label directement sur le <svg> fonctionne aussi, mais le support <title> + aria-labelledby est plus fiable sur l’ensemble des AT testées :
<!-- ✅ Fonctionne, moins robuste -->
<svg role="img" aria-label="Attention : service fermé ce jour" width="20" height="20">
<use href="#icon-alerte"/>
</svg>
role="img" est indispensable dans les deux cas. Sans lui, le lecteur d’écran ne traite pas le SVG comme une image et le <title> n’est pas exposé à l’arbre d’accessibilité.
Pour une font-icon informative seule, l’élément <i> pose un problème structurel : son rôle implicite est generic, et les éléments génériques ne peuvent pas être nommés par ARIA. Mettre aria-label sur un <i> sans role est ignoré par JAWS et NVDA. La correction est d’ajouter role="img" :
<!-- ✅ Font-icon informative : role="img" obligatoire -->
<i class="fa fa-exclamation-triangle" role="img" aria-label="Attention : service fermé ce jour"></i>
En pratique, une icône informative seule sans texte visible est un choix éditorial à questionner. Un texte visible reste préférable à une alternative ARIA que beaucoup d’utilisateurs ne percevront pas.
Icône dans un bouton ou un lien
C’est le cas le plus fréquent, et le plus souvent mal traité. Un bouton ou un lien avec une icône seule (sans texte visible) doit porter son nom accessible sur l’élément interactif lui-même : le <button> ou le <a>.
L’icône, elle, reçoit aria-hidden="true" pour ne pas être annoncée deux fois.
<!-- ✅ Bouton avec icône seule : aria-label sur le bouton, aria-hidden sur l'icône -->
<button type="button" aria-label="Rechercher">
<svg aria-hidden="true" focusable="false" width="16" height="16">
<use href="#icon-loupe"/>
</svg>
</button>
→ NVDA + Firefox : "Rechercher, bouton"
Si le bouton a déjà un texte visible, inutile d’ajouter un aria-label sur le bouton : le texte visible suffit, et l’icône reste masquée :
<!-- ✅ Bouton avec texte visible : aria-hidden suffit sur l'icône -->
<button type="button">
<svg aria-hidden="true" focusable="false" width="16" height="16">
<use href="#icon-loupe"/>
</svg>
Rechercher
</button>
→ NVDA : "Rechercher, bouton"
Les mêmes règles s’appliquent aux liens. Un lien vers les réseaux sociaux avec une icône seule et sans texte visible :
<!-- ✅ Lien réseau social : aria-label descriptif sur le <a> -->
<a href="https://www.facebook.com/exemple" aria-label="Facebook : Commune de X (lien externe)">
<svg aria-hidden="true" focusable="false" width="24" height="24">
<use href="#icon-facebook"/>
</svg>
</a>
L’erreur la plus fréquente : mettre aria-label sur l’élément <svg> ou <i> plutôt que sur le <a>. Le lien reste alors sans nom accessible.
<!-- ❌ aria-label sur le SVG : le lien n'a pas de nom -->
<a href="https://www.facebook.com/exemple">
<svg aria-label="Facebook" width="24" height="24"><!-- ... --></svg>
</a>
→ NVDA : URL complète annoncée comme intitulé du lien
Font Awesome et les bibliothèques d’icônes
Font Awesome génère ses icônes via un pseudo-élément ::before ou ::after sur un élément <i>. Le caractère Unicode de l’icône est injecté en CSS, pas dans le DOM HTML. Le lecteur d’écran se comporte différemment selon les navigateurs : NVDA sous Firefox lit parfois le caractère Unicode brut (un code incompréhensible), NVDA sous Chrome souvent ne lit rien.
Ce comportement imprévisible est la raison pour laquelle aria-hidden="true" est toujours recommandé sur l’élément <i> quand l’icône est décorative ou quand le bouton/lien porte son propre label :
<!-- ✅ Font Awesome décoratif dans un bouton labellisé -->
<button type="button" aria-label="Fermer">
<i class="fa fa-times" aria-hidden="true"></i>
</button>
Pour Font Awesome 6, la documentation officielle recommande d’ajouter la classe fa-sr-only pour fournir un texte caché aux AT, ce qui est équivalent à un texte .sr-only. La méthode aria-hidden + aria-label sur le parent reste plus explicite et plus contrôlée :
<!-- Font Awesome 6 — méthode officielle avec sr-only -->
<button type="button">
<i class="fa-solid fa-times" aria-hidden="true"></i>
<span class="fa-sr-only">Fermer</span>
</button>
<!-- Méthode ARIA directe — équivalente, plus lisible -->
<button type="button" aria-label="Fermer">
<i class="fa-solid fa-times" aria-hidden="true"></i>
</button>
Les deux sont conformes. La méthode fa-sr-only a l’avantage de rester lisible même si les styles CSS ne se chargent pas.
SVG : inline vs élément <img>
Un SVG peut être intégré de deux façons :
SVG en tant qu’élément <img> : traitement identique à une image classique. alt="" pour le décoratif, alt="description" pour l’informatif.
<!-- ✅ SVG comme <img> décoratif -->
<img src="icone.svg" alt="">
<!-- ✅ SVG comme <img> informatif -->
<img src="statut-ouvert.svg" alt="Service ouvert">
SVG inline (<svg> directement dans le HTML) : accès complet aux attributs ARIA, mais la gestion est manuelle.
<!-- ✅ SVG inline décoratif -->
<svg aria-hidden="true" focusable="false">...</svg>
<!-- ✅ SVG inline informatif -->
<svg role="img" aria-labelledby="svg-titre">
<title id="svg-titre">Service ouvert</title>
...
</svg>
Le SVG inline a un avantage : on peut le styler via CSS (couleur, taille) sans dépendre d’un fichier externe. Il a un inconvénient : il alourdit le HTML et les id de <title> doivent être uniques dans la page entière. Si le même icône est répété, les id entrent en conflit.
Emojis
Un emoji dans le corps de texte est lu par le lecteur d’écran avec son nom Unicode officiel. ”🙏” s’entend “Mains pressées ensemble”. ”🚩” s’entend “Drapeau triangulaire sur poteau”. Ce n’est pas toujours ce que l’auteur veut transmettre.
Si l’emoji est purement décoratif (redondant avec le texte adjacent), le masquer :
<!-- ✅ Emoji décoratif masqué -->
<p>Bienvenue <span aria-hidden="true">👋</span></p>
Si l’emoji porte un sens que le texte n’exprime pas, expliciter ce sens via un <span> caché :
<!-- ✅ Emoji informatif : sens explicité -->
<p>
<span aria-hidden="true">🚩</span>
<span class="sr-only">Point d'attention :</span>
Ce délai n'est pas garanti.
</p>
En audit RGAA
Quatre critères couvrent les icônes.
Critère 1.1 : toute image porteuse d’information a-t-elle une alternative textuelle ?
Vérifier chaque <img> et chaque SVG inline non décoratif : alt présent et non vide pour les <img>, role="img" + aria-label ou <title> pour les SVG.
Critère 1.2 : les images décoratives sont-elles correctement ignorées par les AT ?
alt="" sur les <img> décoratives. aria-hidden="true" sur les SVG et font-icons décoratifs. L’attribut alt absent (pas vide) est une erreur : le lecteur d’écran peut lire le nom du fichier.
Critère 6.1 : l’intitulé de chaque lien est-il explicite ?
Un lien icône sans aria-label sur le <a> est non conforme si l’icône seule ne transmet pas la destination. “Facebook” n’est pas suffisant si plusieurs pages Facebook sont présentes. L’intitulé doit décrire la destination, pas l’icône.
Critère 6.2 : chaque lien a-t-il un intitulé ?
Un <a> sans texte visible, sans alt sur l’image enfant et sans aria-label est un lien vide : erreur bloquante.
Checklist
- Chaque
<img>décorative aalt="" - Chaque SVG et font-icon décoratifs ont
aria-hidden="true" - Chaque bouton avec icône seule a un
aria-labelsur le<button> - Chaque lien avec icône seule a un
aria-labelsur le<a> - L’
aria-labeldécrit l’action ou la destination, pas la forme de l’icône - Les SVG inline ont
focusable="false" - Les SVG informatifs ont
role="img"+<title>ouaria-label - Les font-icons ont
aria-hidden="true"quand le parent porte le label - Les emojis décoratifs ont
aria-hidden="true"sur leur élément porteur
Erreurs fréquentes en audit
| Erreur | Critère | Correction |
|---|---|---|
<img> décorative sans alt ou avec alt non vide | 1.2 | alt="" |
SVG décoratif sans aria-hidden="true" | 1.2 | Ajouter aria-hidden="true" sur <svg> |
Font-icon sans aria-hidden="true" | 1.2 | Ajouter aria-hidden="true" sur <i> ou <span> |
aria-label sur le <svg> ou <i> au lieu du <a> ou <button> | 6.2 | Déplacer le aria-label sur l’élément interactif |
aria-label sur <i> ou <span> sans role="img" | 7.1 | Ajouter role="img" si l’icône doit être restituée comme image |
| Lien réseau social “Facebook” sans nom de l’organisation | 6.1 | aria-label="Facebook : Commune de X" |
Alt du logo décrivant l’apparence (alt="Logo") | 1.1 | Alt décrivant la destination (alt="Accueil : Commune de X") |
Lien avec <img alt=""> seule, sans aria-label sur le <a> | 6.2 | Lien entièrement vide pour les AT, ajouter aria-label sur le <a> |