css-hidden-focus

Les éléments focalisables ne doivent pas être masqués visuellement

manualWCAG 2.4.7 (AA)confiance : lowgravité : seriousoperable

Vérifie que les éléments pouvant recevoir le focus clavier ne sont pas masqués visuellement par des techniques CSS susceptibles de les laisser dans l’ordre de tabulation.

Applicabilité. S’applique aux éléments tabulables (pouvant recevoir le focus clavier) mais masqués visuellement par des techniques CSS susceptibles de les laisser dans l’ordre de tabulation.

Attendu. Aucun élément ne devrait être tabulable tout en étant masqué visuellement (p. ex. opacity:0, découpé, hors écran). Un élément que le CSS ramène à l’écran lorsqu’il reçoit le focus n’est pas masqué tant qu’il a le focus, et n’est pas signalé : le motif habituel du lien d’évitement (.skip { position: absolute; left: -9999px } .skip:focus { left: 0 }), ou une règle de masquage qui cesse de s’appliquer au focus (.visually-hidden-focusable:not(:focus) { clip: rect(0 0 0 0) }). Une règle de focus imbriquée dans une autre (.skip { &:focus { top: 0 } }) compte comme si elle était écrite en entier ; une règle dont le focus se trouve dans :has() compte, pour son sujet, comme le fait :focus-within. Une règle de focus qui n’est pas !important ne l’emporte pas sur une déclaration !important qui masque l’élément.

Ce que rapporte un constat.

  • metrics.visibilityHints : la façon dont l’élément est masqué alors qu’il peut recevoir le focus : opacityZero, offscreen, clipped ou zeroSizeOverflowHidden (sans taille, avec overflow masqué) par ses propres styles ; lorsque ceux-ci l’affichent, outOfReach (un conteneur est positionné hors écran ou, dans un navigateur, la boîte qu’afficherait le focus se trouve là où aucun défilement n’arrive) ou containerClipped (un conteneur est découpé à néant, n’a pas de taille avec overflow masqué, ou est mis à l’échelle à néant ou, dans un navigateur, l’élément se trouve entièrement hors d’un conteneur en overflow: clip, que le focus ne fait pas défiler).
  • runtimeProbe : null sauf si donner le focus à l’élément a fait passer le focus directement à un autre élément (cssHiddenTabbable_runtimeRedirect_needsReview). Il contient alors redirected: true ainsi que la balise et l’id de l’élément vers lequel le focus est passé (redirectedToTag, redirectedToId). Seuls les trois premiers éléments masqués sont testés ainsi.

Ces champs de data.details aident à lire et à reproduire un constat. À part reasonCode et les quelques champs que la page Schéma de sortie donne comme stables, ils ne constituent pas un contrat stable : un champ peut être renommé ou supprimé dans une version mineure, ne vous appuyez donc pas dessus.

Exemples

can't tell
<a href="/x" style="opacity:0;">Hidden but tabbable link</a>

Le lien reste dans l’ordre de tabulation alors qu’opacity:0 le rend invisible aux personnes voyantes qui naviguent au clavier.

n/a
<a href="/x">Visible link</a>

Le lien peut recevoir le focus et il est visible : rien à signaler.

n/a
<style>.skip { position: absolute; left: -9999px; } .skip:focus { left: 0; }</style>
<a class="skip" href="#main">Skip to content</a>

Le lien est hors écran au repos, mais sa règle :focus le ramène à l’écran lorsqu’il reçoit le focus.

Comment vérifier

Quand cette règle ne peut pas trancher, elle renvoie cantTell et laisse la question à une personne. Chaque question qu’elle peut poser figure ici sous son code de raison, avec les étapes pour y répondre. Un constat porte les mêmes étapes dans howToCheck, dans la langue de l’analyse. Voir Schéma de sortie.

cssHiddenTabbable_needsFocusStateVerification

  1. Cliquez juste avant l’élément indiqué par le rapport, puis appuyez sur Tab jusqu’au moment où le focus devrait l’atteindre.
  2. Vérifiez document.activeElement dans la console des outils de développement pour vous assurer que le focus est sur lui.
  3. Cherchez l’élément et son indicateur de focus à l’écran.

Réussite. L’élément apparaît avec un indicateur de focus visible tant qu’il a le focus.

Échec. Le focus arrive sur l’élément alors qu’il reste masqué : l’utilisateur du clavier ne voit pas où est le focus, ce qui ne respecte pas le critère WCAG 2.4.7.

cssHiddenTabbable_runtimeRedirect_needsReview

  1. Cliquez juste avant l’élément indiqué par le rapport, puis appuyez sur Tab jusqu’au moment où le focus devrait l’atteindre.
  2. Regardez où arrive le focus et vérifiez document.activeElement dans la console des outils de développement.
  3. Appuyez sur Maj+Tab depuis le contrôle suivant et voyez si le focus s’arrête sur l’élément masqué ou passe directement.

Réussite. Le focus ne reste jamais sur l’élément masqué : il passe directement à un contrôle visible, comme le fait la sentinelle d’un piège à focus.

Échec. Le focus peut rester sur l’élément masqué : l’utilisateur du clavier ne voit pas où est le focus, ce qui ne respecte pas le critère WCAG 2.4.7.

Voir le code source