Chapitre 6.5 — Les erreurs fréquentes
⏱️ TL;DR — La plupart des dégâts d’ARIA viennent d’une poignée d’erreurs qui reviennent partout : rôle redondant,
aria-hiddensur un élément focusable (piège de focus),aria-labelledbyqui pointe unidinexistant,aria-labelsur un élément non interactif (ignoré), rôle natif écrasé, nom doublé (texte visible ≠aria-label), et live regions en surdose. Ce chapitre les liste avec, pour chacune, pourquoi c’est un problème et comment corriger. Fais-en ta checklist d’audit.
🎯 Objectifs
- Reconnaître les sept erreurs ARIA les plus courantes en un coup d’œil.
- Expliquer, pour chacune, ce qu’elle casse pour l’utilisateur.
- Appliquer le correctif exact — souvent : retirer de l’ARIA.
- Te constituer une checklist d’audit ARIA réutilisable.
1. Le rôle redondant
Répéter un rôle que la balise porte déjà : <button role="button">, <nav role="navigation">, <ul role="list"><li role="listitem">. Problème : ce n’est pas fatal, mais c’est du bruit qui trahit une incompréhension et masque les vrais besoins. Correctif : supprime le role, laisse le natif parler.
<!-- ❌ --> <button role="button">Envoyer</button>
<!-- ✅ --> <button>Envoyer</button>2. aria-hidden sur un élément focusable
Poser aria-hidden="true" sur un élément qui peut recevoir le focus (<a>, <button>, <input>, ou tout tabindex="0"). Problème : c’est la règle n°4 d’ARIA violée. L’élément devient un fantôme — atteignable au clavier (l’utilisateur y arrive avec Tab) mais invisible au lecteur d’écran, qui n’annonce rien. L’utilisateur est « quelque part » sans savoir où. Correctif : ne masque jamais un interactif ; si tu veux vraiment le retirer, retire-le aussi de la tabulation (tabindex="-1") — ou mieux, ne le rends pas focusable.
<!-- ❌ Fantôme : focusable mais muet -->
<button aria-hidden="true">Fermer</button>
<!-- ✅ Soit visible pour tous, soit vraiment hors d'atteinte -->
<button>Fermer</button>3. aria-labelledby (ou describedby) vers un id inexistant
Référencer un id qui n’existe pas, ou avec une faute de frappe. Problème : la référence est silencieusement ignorée. L’élément se retrouve sans nom accessible — le lecteur d’écran annonce « bouton » tout court. Aucune erreur console ne t’alerte. Correctif : vérifie que chaque id référencé existe et est unique dans la page.
<!-- ❌ Aucun élément #titre-modal → nom vide -->
<div role="dialog" aria-labelledby="titre-modal">…</div>
<!-- ✅ La cible existe -->
<div role="dialog" aria-labelledby="titre-modal">
<h2 id="titre-modal">Confirmer la suppression</h2>
</div>4. aria-label sur un élément non interactif
Coller aria-label sur une <div>, un <span>, un <p> sans rôle. Problème : sur un élément non interactif et sans rôle, aria-label est tout simplement ignoré par la plupart des lecteurs d’écran. Tu crois avoir nommé quelque chose, mais l’annonce n’existe pas. aria-label ne fonctionne que sur les éléments interactifs ou porteurs d’un rôle (bouton, lien, champ, landmark, widget). Correctif : mets le texte dans le contenu, ou donne d’abord un rôle à l’élément.
<!-- ❌ Ignoré : une <div> nue n'expose pas de nom -->
<div aria-label="Statistiques du mois">…</div>
<!-- ✅ Le texte est réellement exposé -->
<section aria-label="Statistiques du mois">…</section>5. Le rôle natif écrasé
Mettre un role qui détruit la sémantique native : <h2 role="button"> (plus un titre), <a role="button"> (plus un lien), <li role="presentation"> (liste disloquée). Problème : tu casses la navigation par titres, par liens ou la structure de liste (voir 6.2). Correctif : n’écrase jamais un rôle utile ; imbrique plutôt l’élément interactif à l’intérieur du natif.
6. Le nom doublé (ou divergent)
Un élément a un texte visible et un aria-label différent. Problème : le aria-label écrase le texte visible dans l’arbre. L’utilisateur voit « Envoyer » mais son lecteur d’écran dit « Valider le formulaire » — décalage déroutant, et surtout échec de la commande vocale : quelqu’un qui dit « clique sur Envoyer » ne déclenche rien, car le nom accessible est « Valider le formulaire ». Correctif : soit tu n’ajoutes pas d’aria-label (le texte visible suffit), soit tu fais en sorte que le nom accessible contienne le texte visible.
<!-- ❌ Ce qu'on voit ≠ ce qu'on entend → casse la commande vocale -->
<button aria-label="Valider le formulaire">Envoyer</button>
<!-- ✅ Le texte visible EST le nom accessible -->
<button>Envoyer</button>⚠️ Piège — Le nom accessible qui ne contient pas le libellé visible. C’est le critère WCAG 2.5.3 (Étiquette dans le nom) : quand un contrôle a un texte visible, son nom accessible doit inclure ce texte. Sinon les utilisateurs de commande vocale ne peuvent plus l’activer par son nom affiché. Ne « corrige » jamais un libellé visible avec un
aria-labelqui dit autre chose.
7. L’abus de live regions
Multiplier les aria-live="assertive", ou brancher une live region sur une zone qui change en permanence (chrono, flux temps réel). Problème : le lecteur d’écran coupe la parole sans arrêt ou débite un flot ininterrompu — l’utilisateur ne peut plus rien lire. Correctif : réserve assertive à l’urgent, préfère polite, temporise les mises à jour (voir 6.4).
Tableau récapitulatif : erreur → correctif
| Erreur | Ce que ça casse | Correctif |
|---|---|---|
Rôle redondant (<button role="button">) | Bruit, incompréhension | Supprimer le role |
aria-hidden sur un focusable | Fantôme : focusable mais muet | Retirer aria-hidden (ou tabindex="-1") |
aria-labelledby → id inexistant | Nom accessible vide | Vérifier l’existence + unicité de l’id |
aria-label sur non-interactif | Attribut ignoré | Mettre le texte en contenu, ou donner un rôle |
Rôle natif écrasé (<h2 role="button">) | Navigation par titres/liens cassée | Imbriquer l’interactif dans le natif |
Nom doublé (visible ≠ aria-label) | Décalage + commande vocale KO | Nom accessible = texte visible |
| Abus de live regions | Lecteur d’écran qui coupe/spamme | polite par défaut, temporiser |
💡 Réflexe — En audit, ta première hypothèse face à un attribut ARIA n’est pas « est-il correct ? » mais « est-il nécessaire ? ». La majorité des correctifs de ce chapitre consistent à retirer de l’ARIA, pas à en ajouter. Rappelle-toi la maxime : No ARIA better than bad ARIA. Le meilleur code ARIA est souvent celui qu’on efface.
🧭 Sur A11yLearn — Un audit rapide d’A11yLearn a sorti quatre de ces sept erreurs : un
aria-hidden="true"sur l’icône focusable de fermeture des modales (fantôme), deuxaria-labelledbypointant desidrenommés lors d’un refactor (noms vides), et un bouton « Envoyer » relabellisé « Soumettre le formulaire » (commande vocale cassée). Aucun ne s’est réparé en ajoutant de l’ARIA : trois suppressions et une correction d’id. C’est la règle : sur A11yLearn, on ouvre chaque ticket ARIA par la question « peut-on juste l’enlever ? ».
📚 Aller plus loin — Ces motifs sont exactement ce que remontent les outils comme axe-core (règles
aria-hidden-focus,aria-valid-attr-value,aria-required-attr…). Les critères WCAG concernés : 4.1.2 (Nom, rôle, valeur) et 2.5.3 (Étiquette dans le nom). Pour outiller ton audit, voir Partie 14 — Tester et le Cookbook.
✏️ Exercices
Exercice 1 — Trois erreurs dans un bloc. Repère et corrige tous les problèmes ARIA de ce code.
<a href="/aide" role="button" aria-label="Ouvrir l'aide">Aide</a>
<span aria-label="Nombre de notifications">3</span>
<button aria-hidden="true" tabindex="0">Fermer</button>✅ Solution
- Le lien :
role="button"écrase le rôle « lien » (erreur 5) etaria-label="Ouvrir l'aide"diverge du texte visible « Aide » (erreur 6, commande vocale cassée). Correctif :<a href="/aide">Aide</a>. - Le
<span>:aria-labelsur un élément non interactif est ignoré (erreur 4). Correctif : mettre le contexte en texte réel, ex.<span>3 notifications</span>. - Le bouton :
aria-hidden="true"sur un élément focusable (tabindex="0") = fantôme (erreur 2). Correctif :<button>Fermer</button>.
Bilan : les trois corrections retirent de l’ARIA. C’est le motif dominant.
Exercice 2 — Pourquoi ce bouton n’a-t-il pas de nom ? Le lecteur d’écran annonce juste « bouton ». Diagnostique.
<button aria-labelledby="lbl-fermer"></button>✅ Solution
aria-labelledby pointe vers l’id lbl-fermer, mais aucun élément ne porte cet id dans la page (erreur 3). La référence est silencieusement ignorée — pas d’erreur console — et le bouton, vide de texte, se retrouve sans nom accessible. Correctif : soit créer l’élément #lbl-fermer, soit donner un nom direct : <button aria-label="Fermer"></button> (ici aria-label est légitime : le bouton est interactif et n’a pas de texte visible).
🧠 Quiz de révision
1. Pourquoi aria-hidden="true" sur un bouton focusable est-il grave ?
aria-hidden="true" sur un bouton focusable est-il grave ?Ça crée un fantôme : l’utilisateur clavier atteint l’élément avec Tab, mais le lecteur d’écran n’annonce rien (il est masqué de l’arbre). Il se retrouve « quelque part » sans savoir où. C’est la règle n°4 d’ARIA violée. Correctif : retirer aria-hidden, ou le sortir aussi de la tabulation.
2. Que se passe-t-il si aria-labelledby pointe un id inexistant ?
aria-labelledby pointe un id inexistant ?La référence est silencieusement ignorée (aucune erreur console) et l’élément se retrouve sans nom accessible : le lecteur d’écran annonce juste son rôle. Il faut vérifier que chaque id référencé existe et est unique.
3. Pourquoi aria-label sur une <div> nue ne marche-t-il pas ?
aria-label sur une <div> nue ne marche-t-il pas ?Parce que aria-label n’est exposé que sur les éléments interactifs ou porteurs d’un rôle. Sur une <div>/<span> sans rôle, il est ignoré par la plupart des lecteurs d’écran. On met le texte en contenu, ou on donne d’abord un rôle (ou une balise sémantique comme <section>).
4. Quel critère interdit qu’un aria-label diverge du texte visible ?
aria-label diverge du texte visible ?Le critère WCAG 2.5.3 (Étiquette dans le nom) : quand un contrôle a un libellé visible, son nom accessible doit contenir ce libellé. Sinon la commande vocale ne peut plus l’activer par son nom affiché, et l’annonce déroute l’utilisateur.
5. Quel est le réflexe commun à la majorité des correctifs ARIA ?
Retirer de l’ARIA plutôt qu’en ajouter. Rôle redondant, aria-hidden de trop, rôle écrasant, aria-label divergent : la plupart se réparent par une suppression. « No ARIA better than bad ARIA » — la première question d’audit est « est-ce nécessaire ? », pas « est-ce correct ? ».
Fin de la Partie 6. On enchaîne avec Partie 7 — Texte, couleur & contraste : rendre le contenu lisible pour tous, ARIA ou pas.