Pour chaque page web, les contenus cachés ont-ils vocation à être ignorés par les technologies d’assistance ?
Un menu déroulant s’ouvre au clic. Pour un utilisateur voyant, les options apparaissent. Pour un utilisateur de lecteur d’écran, si le contenu reste marqué aria-hidden="true", il n’existe pas. Le menu s’est ouvert, le lecteur d’écran est resté muet.
Ce critère distingue deux situations légitimes. Soit le contenu caché doit rester ignoré par les technologies d’assistance — un compteur de visites animé, une illustration décorative — et dans ce cas le masquage est voulu. Soit le contenu caché deviendra utile à un moment donné — une modale, un sous-menu, un panneau d’accordéon — et il doit pouvoir être restitué : via une action clavier sur un élément précédant le contenu, ou via un repositionnement programmatique du focus.
La technique de masquage détermine directement l’accessibilité. display: none et l’attribut hidden retirent le nœud de l’arbre d’accessibilité. aria-hidden="true" fait la même chose sans modifier le rendu visuel. visibility: hidden retire aussi le contenu des AT. À l’inverse, la classe .sr-only masque visuellement tout en maintenant le contenu lisible par les lecteurs d’écran.
Vérifiez chaque élément portant hidden, aria-hidden, ou un style CSS de masquage. Une seule question : cet élément a-t-il vocation à rester invisible aux AT ? S’il doit un jour devenir accessible, le mécanisme pour y parvenir est-il opérable au clavier ?
Un test pour vérifier la gestion correcte des contenus masqués
Accessibilité des contenus cachés aux AT
- Repérez tous les contenus cachés sur la page : éléments avec l’attribut
hidden, avecaria-hidden="true", ou avec un style CSS de masquage (display: none,visibility: hidden, classe.sr-only, etc.). - Pour chaque contenu caché, tranchez entre deux cas :
- Cas A — Ignoré intentionnellement : le contenu n’apporte rien aux utilisateurs d’AT (animation décorative, compteur de statistiques). Le masquage est justifié. ✓
- Cas B — Masqué temporairement : le contenu sera utile une fois révélé (modale, sous-menu, accordéon). Vérifiez qu’une des deux conditions est remplie : a. Une action clavier (ou dispositif de pointage) sur un élément situé avant le contenu dans le DOM révèle ce contenu aux AT. b. Une fonction JavaScript repositionne le focus sur le contenu au moment où il devient pertinent.
- Si tous les contenus cachés relèvent du Cas A ou du Cas B correctement implémenté, le test est validé. Un seul contenu ne respectant aucun des deux cas suffit à faire échouer le test.
Exemples
❌ Non conforme : Modale masquée définitivement aux AT lors de l’ouverture
<button onclick="showModal()">Ouvrir les conditions</button>
<div id="modal" aria-hidden="true">
<h2>Conditions générales d’utilisation</h2>
<p>En utilisant ce service, vous acceptez nos termes.</p>
<button onclick="closeModal()">Fermer</button>
</div>
<script>
function showModal() {
document.getElementById('modal').style.display = 'block';
// aria-hidden="true" reste en place — le contenu n'est jamais restitué
}
function closeModal() {
document.getElementById('modal').style.display = 'none';
}
</script>La modale devient visible à l’écran, mais aria-hidden="true" n’est jamais supprimé. Un utilisateur de lecteur d’écran active le bouton, rien ne change dans l’arbre d’accessibilité. Les conditions générales — contenu potentiellement obligatoire — sont totalement inaccessibles.
✅ Conforme : Modale accessible avec suppression de aria-hidden et gestion du focus
<button id="open-btn" onclick="showModal()">Ouvrir les conditions</button>
<div id="modal" aria-hidden="true" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<h2 id="modal-title">Conditions générales d’utilisation</h2>
<p>En utilisant ce service, vous acceptez nos termes.</p>
<button id="close-btn" onclick="closeModal()">Fermer</button>
</div>
<script>
function showModal() {
const modal = document.getElementById('modal');
modal.removeAttribute('aria-hidden');
modal.style.display = 'block';
document.getElementById('close-btn').focus();
}
function closeModal() {
const modal = document.getElementById('modal');
modal.setAttribute('aria-hidden', 'true');
modal.style.display = 'none';
document.getElementById('open-btn').focus();
}
</script>À l’ouverture, aria-hidden est supprimé et le focus se déplace dans la modale. Le lecteur d’écran annonce immédiatement le titre du dialogue. À la fermeture, le focus revient sur le bouton déclencheur. Cycle complet, aucune perte d’information.
✅ Conforme : Contenu ignoré intentionnellement : animation de compteur
<div aria-hidden="true" class="stats-counter-animation">
<span class="counter" data-target="15420">0</span> visites
</div>
<p>Plus de <strong>15 000 utilisateurs</strong> font confiance à notre service.</p>L’animation de compteur (0 → 15 420) n’apporte rien aux AT : le lecteur d’écran lirait chaque valeur intermédiaire, créant du bruit inutile. L’information réelle est fournie dans le paragraphe suivant sous forme de texte statique. aria-hidden="true" est ici volontaire et justifié.
Astuces et pièges
⚠️ aria-hidden se propage à tous les descendants sans exception
Poser aria-hidden="true" sur un <div> parent masque l’intégralité de ses enfants aux AT, même s’ils portent role, aria-label ou d’autres attributs ARIA explicites. Les DevTools Chrome l’indiquent explicitement : « Accessibility node not exposed, aria-hidden is true on ancestor ». Vérifiez toujours la portée avant d’appliquer l’attribut sur un conteneur.
⚠️ Un élément aria-hidden peut rester focusable au clavier
aria-hidden="true" ne retire pas l’élément du parcours clavier. Un bouton ou un lien dans un panneau masqué aux AT recevra toujours le focus avec Tab. L’utilisateur se retrouve dans un trou noir : le curseur disparaît visuellement sans annonce. Si un contenu doit être masqué aux AT, ses enfants interactifs doivent aussi être rendus non focusables via tabindex="-1" ou l’attribut inert.
💡 Auditer avec l’arbre d’accessibilité du navigateur
Dans les DevTools de Chrome ou Firefox, l’onglet Accessibility affiche l’arbre d’accessibilité en temps réel. Un élément absent de l’arbre ou marqué « not exposed » est effectivement ignoré par les lecteurs d’écran. C’est la vérification la plus rapide, plus fiable qu’un test complet avec un lecteur d’écran pour ce critère.
⚠️ .sr-only expose le contenu aux AT, pas l’inverse
La classe .sr-only (ou .visually-hidden) masque visuellement tout en maintenant le contenu dans l’arbre d’accessibilité. L’erreur survient quand on l’applique à du contenu décoratif : le lecteur d’écran annonce alors du bruit inutile. Le critère 10.8 joue dans les deux sens : contenu utile masqué aux AT, et contenu décoratif exposé aux AT, sont tous deux des problèmes.
⚠️ Les animations CSS seules ne masquent pas aux AT
Un élément avec opacity: 0 ou transform: scale(0) reste généralement dans l’arbre d’accessibilité et sera lu par les lecteurs d’écran. Si votre animation de transition laisse un élément à opacity: 0 entre deux états, ajoutez aria-hidden="true" pendant cet état intermédiaire, ou utilisez display: none à la fin de la transition.
Questions fréquentes
Quelle différence entre display: none et aria-hidden="true" pour masquer du contenu selon le RGAA ?
display: none et l’attribut hidden masquent le contenu visuellement ET le retirent de l’arbre d’accessibilité. aria-hidden="true" retire uniquement de l’arbre d’accessibilité — le contenu reste visible à l’écran. Le critère 10.8 s’applique aux deux : si ce contenu n’a pas vocation à rester ignoré par les AT, il doit être rendu accessible via une action clavier ou un repositionnement du focus, quelle que soit la technique de masquage.
Comment vérifier qu'un contenu masqué est bien ignoré par les technologies d'assistance ?
Ouvrez les DevTools, inspectez l’élément, accédez à l’onglet Accessibility. Un élément absent de l’arbre d’accessibilité ou affichant « not exposed » est effectivement ignoré. Pour les contenus dynamiques (modales, menus), déclenchez l’ouverture et vérifiez que l’arbre se met à jour, que aria-hidden est supprimé, et que le focus se déplace bien dans le contenu révélé.
Comment évaluer un accordéon masqué par défaut selon le critère RGAA 10.8 ?
Oui, à deux conditions. Le bouton déclencheur doit précéder le panneau dans le DOM et porter aria-expanded pour indiquer l’état. À l’ouverture, le contenu doit être restitué aux AT : soit par suppression de aria-hidden (le contenu suit immédiatement le bouton dans le flux AT), soit par repositionnement du focus dans le panneau. La présence seule d’aria-expanded ne suffit pas si le contenu reste marqué aria-hidden="true".
Comment opacity: 0 affecte-t-il la perception du contenu par les technologies d'assistance ?
Non, pas de façon fiable. Un élément avec opacity: 0 reste généralement dans l’arbre d’accessibilité et sera lu par les lecteurs d’écran. Pour masquer aux AT, utilisez display: none, hidden, ou aria-hidden="true". Pour masquer visuellement tout en maintenant l’accessibilité, utilisez .sr-only. transform: scale(0) se comporte comme opacity: 0 : visible aux AT.
Comment le critère RGAA 10.8 s'applique-t-il aux composants tiers comme chatbots et bandeaux cookies ?
Oui, il s’applique à toute la page, y compris les widgets externes. Ces composants génèrent fréquemment des violations 10.8 car ils gèrent mal aria-hidden ou le focus lors de l’affichage de leurs panneaux. Si vous ne contrôlez pas le code, signalez le problème au prestataire et documentez l’exception dans votre déclaration d’accessibilité avec un calendrier de correction.