La classe de masquage accessible .visually-hidden
— anciennement .sr-only
dans Bootstrap — a beaucoup évolué au fil du temps. C’est pour ça que j’ai publié cache-cache CSS il y a quelques années, qui récapitulait l’état de l’art à ce moment.
Mais il n’y a pas que les techniques CSS qui évoluent… Les navigateurs, aussi. Et parfois, ça requièrs de l’adaptation !
Un cas légendaire
Louis-Maxime Piton — un des mainteneurs de Boosted (en anglais) et inévitablement contributeur à Bootstrap (en anglais) — a proposé un correctif (sur GitHub, en anglais) il y a plus de deux ans pour contourner un problème provoqué par le masquage accessible appliqué à une légende de tableau (sur StackOverflow, en anglais).
Les caption
, lorsqu’ils sont en position absolue, sont considérés comme des cellules de tableaux anonymes — et ça met la grouille dans la fusion des bordures, l’indispensable border-collapse: collapse
.
Le correctif proposé est simplissime, bien qu’il puisse théoriquement poser des problèmes : n’appliquer la position absolue que si l’élément n’est pas un caption
. C’est l’état actuel du mixin dans Bootstrap (sur GitHub, en anglais).
En résumé, voici la modification :
.visually-hidden:not(caption) {
position: absolute !important;
}
En cas de débordement
La semaine dernière, l’ami Django Janny a relancé le sujet sur Gist (en anglais) avec un cas marginal : un élément qui déborde, à l’intérieur d’un élément masqué visuellement.
En général, on ne masque qu’une portion de texte de cette façon : aucun élément bloc ne devrait s’y trouver — ni, en réalité, aucun enfant. La majorité du temps, le masquage accessible respecte implicitement les mêmes règles qu’un attribut aria-label
par exemple : un texte simple et concis.
Mais c’est une règle implicite, et à ma connaissance aucune contre-indication n’a jamais été mentionnée quant à l’utilisation du masquage accessible sur une portion de DOM plus riche. Je l’ai par exemple fait lorsque j’ai amélioré les liens d’évitements sur la documentation de Bootstrap (en anglais), dont le conteneur est masqué visuellement — mais il apparaît à la prise de focus, nous faisant passer à côté du problème…
Depuis (au moins) 2019, les éléments en débordement deviennent focusables dans la plupart des navigateurs, pour palier un défaut d’accessibilité : ne pas pouvoir interagir avec un élément masqué par un débordement. Cassey Lottman a retracé ce changement dans son article Elements with overflow: scroll become focusable (en anglais).
Ce qui, dans un élément masqué visuellement, devient un piège : on ne voit (évidemment) pas le focus.
La solution proposée par Django — et après quelques tests, la seule qui paraisse fonctionner — est d’empêcher le débordement sur les enfants d’un élément masqué visuellement (sur CodePen, en anglais) :
.visually-hidden * {
overflow: hidden !important;
}
La totale
Voici donc la version mise à jour de la technique de masquage accessible :
.visually-hidden,
.visually-hidden-focusable:not(:focus, :focus-within) {
border: 0 !important;
clip-path: inset(50%) !important;
height: 1px !important;
margin: -1px !important;
overflow: hidden !important;
padding: 0 !important;
width: 1px !important;
white-space: nowrap !important;
}
.visually-hidden:not(caption),
.visually-hidden-focusable:not(caption):not(:focus, :focus-within){
position: absolute !important;
}
.visually-hidden *,
.visually-hidden-focusable:not(:focus, :focus-within) * {
overflow: hidden !important;
}
J’en ai profité pour proposer ce changement dans Bootstrap (sur GitHub, en anglais) — en citant Django bien entendu — et pour mettre à jour le Gist servant souvent de référence (en anglais).
Notez par ailleurs quelques autres changements succincts :
- J’ai renommé
.sr-only
en.visually-hidden
pour me conformer aux usages des frameworks populaires, - Et nettoyé un peu le support de navigateurs anciens : plus de
clip
désormais, carclip-path
est très largement supporté. - La variante pour démasquer le contenu lors de la prise de focus n’est plus une remise à zéro, mais une autre classe conditionnée à l’état :
.visually-hidden-focusable:not(:focus, :focus-within)
, à l’instar de ce qui est fait dans Bootstrap depuis cinq ans déjà (sur GitHub, en anglais) mais avec la syntaxe moderne de:not()
.
Laisser un commentaire