# Un attribut aria-hidden oublié qui rend un menu mobile fermé toujours lisible

> Le menu est visuellement masqué à l'écran mais un lecteur d'écran continue de l'annoncer comme s'il était ouvert. La cause tient à un oubli récurrent.

- Auteur : WordPress Développement
- Publié le : 2021-07-04
- Mis à jour le : 2021-07-04
- Catégorie : Accessibilité
- URL : https://www.wpmoderne.fr/accessibilite/aria-hidden-oublie-menu-mobile-ferme/

## L’essentiel

- display: none masque visuellement mais pas toujours le DOM lu par le lecteur
- aria-hidden doit refléter l'état visuel réel du menu
- Synchroniser l'attribut avec la classe d'ouverture en JavaScript

« NVDA annonce les liens du menu alors que je ne le vois même pas à l'écran » : ce retour de test revient régulièrement sur des menus mobiles construits avec une simple classe CSS pour basculer l'affichage. Le menu est bien masqué visuellement — la personne voyante ne voit rien d'anormal — mais un lecteur d'écran continue de parcourir et d'annoncer chaque lien du menu, comme si celui-ci était pleinement ouvert et visible.

## Symptôme

Un menu hamburger, fermé par défaut, utilise une classe CSS du type `.menu--ferme` qui applique `max-height: 0; overflow: hidden;` ou une transformation de translation hors écran, pour permettre une animation d'ouverture fluide. Visuellement, rien ne dépasse. Mais en navigant avec un lecteur d'écran en mode exploration, chaque lien du menu est annoncé normalement, y compris lorsque le bouton hamburger affiche encore l'état « fermé ».

## Diagnostic

> L'essentiel à retenir : display: none masque visuellement mais pas toujours le DOM lu par le lecteur ; aria-hidden doit refléter l'état visuel réel du menu ; Synchroniser l'attribut avec la classe d'ouverture en JavaScript

Le masquage visuel par CSS (`overflow: hidden`, translation, opacité à zéro sans `display: none`) ne retire pas nécessairement l'élément de l'arbre d'accessibilité exposé aux technologies d'assistance. Seules certaines propriétés CSS précises (`display: none`, `visibility: hidden`) sont interprétées par les navigateurs comme un signal de retrait de l'arbre d'accessibilité. Une animation d'ouverture qui repose sur `max-height` ou une transformation ne déclenche pas ce retrait : le contenu reste dans le DOM, actif et lisible, alors même qu'il est invisible à l'écran.

C'est exactement ce qui se produit sur ce menu : l'animation CSS choisie pour un rendu visuel fluide laisse le menu techniquement « ouvert » pour les technologies d'assistance, tant qu'aucun attribut `aria-hidden="true"` n'est appliqué explicitement à l'état fermé.

## Correctif

La correction consiste à synchroniser l'attribut `aria-hidden` avec l'état réel du menu, dans le même bloc JavaScript qui gère déjà l'ouverture et la fermeture visuelle :

```
const bouton = document.querySelector('.menu-toggle');
const menu = document.querySelector('.menu-mobile');

function basculerMenu(ouvert) {
  menu.classList.toggle('menu--ouvert', ouvert);
  menu.setAttribute('aria-hidden', ouvert ? 'false' : 'true');
  bouton.setAttribute('aria-expanded', ouvert ? 'true' : 'false');

  // Empêche aussi la tabulation vers les liens masqués
  menu.querySelectorAll('a').forEach((lien) => {
    lien.setAttribute('tabindex', ouvert ? '0' : '-1');
  });
}

bouton.addEventListener('click', () => {
  const estOuvert = menu.classList.contains('menu--ouvert');
  basculerMenu(!estOuvert);
});

// État initial
basculerMenu(false);
```

Le point souvent négligé est la ligne sur `tabindex` : sans elle, même avec `aria-hidden="true"` correctement posé, un utilisateur au clavier peut encore tabuler jusqu'à un lien masqué visuellement, ce qui crée une confusion différente mais tout aussi problématique.

## Vérification

Le test de non-régression consiste à ouvrir les outils de développement, section accessibilité, et vérifier que l'arbre d'accessibilité du menu passe bien de « caché » à « visible » lors du clic sur le bouton hamburger. Un second test à la tabulation seule, menu fermé, doit confirmer qu'aucun lien du menu n'est atteint avant le prochain élément visible de la page.

## Prévention

- Ne jamais considérer qu'un masquage visuel équivaut automatiquement à un masquage pour les technologies d'assistance.
- Centraliser la logique d'ouverture/fermeture dans une seule fonction qui met à jour classe CSS, `aria-hidden`, `aria-expanded` et `tabindex` ensemble, jamais séparément.
- Ajouter ce cas précis à la checklist de recette de tout nouveau composant de menu, avant même de tester le rendu visuel sur mobile.

> Un menu invisible à l'œil n'est pas forcément invisible pour un lecteur d'écran : seule la synchronisation explicite des attributs ARIA avec l'état visuel garantit la cohérence entre les deux mondes.

## En résumé

L'oubli d'`aria-hidden` sur un menu mobile fermé est l'un des bugs d'accessibilité les plus silencieux, car il ne se voit jamais sur un écran classique. Centraliser la bascule d'état dans une seule fonction qui synchronise CSS, ARIA et tabulation évite ce piège de façon durable, sur ce menu comme sur tout futur composant construit sur le même modèle.
