Skip to Content

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-hidden sur un élément focusable (piège de focus), aria-labelledby qui pointe un id inexistant, aria-label sur 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-label qui 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

ErreurCe que ça casseCorrectif
Rôle redondant (<button role="button">)Bruit, incompréhensionSupprimer le role
aria-hidden sur un focusableFantôme : focusable mais muetRetirer aria-hidden (ou tabindex="-1")
aria-labelledbyid inexistantNom accessible videVérifier l’existence + unicité de l’id
aria-label sur non-interactifAttribut ignoréMettre le texte en contenu, ou donner un rôle
Rôle natif écrasé (<h2 role="button">)Navigation par titres/liens casséeImbriquer l’interactif dans le natif
Nom doublé (visible ≠ aria-label)Décalage + commande vocale KONom accessible = texte visible
Abus de live regionsLecteur d’écran qui coupe/spammepolite 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), deux aria-labelledby pointant des id renommé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

  1. Le lien : role="button" écrase le rôle « lien » (erreur 5) et aria-label="Ouvrir l'aide" diverge du texte visible « Aide » (erreur 6, commande vocale cassée). Correctif : <a href="/aide">Aide</a>.
  2. Le <span> : aria-label sur un élément non interactif est ignoré (erreur 4). Correctif : mettre le contexte en texte réel, ex. <span>3 notifications</span>.
  3. 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 ?

Ç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 ?

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 ?

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 ?

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.

Last updated on