Et j’ai beau trouver ça idiot — masquer du texte pour certains utilisateurs et pas pour d’autres, ça me paraît incohérent avec l’accessibilité — c’est un besoin récurrent.
Il existe de nombreuses façons de faire, que je ne détaillerai pas ici. Depuis quelques années, lorsque je le peux, j’utilise celle de Thierry Koblentz pour Yahoo! qui est décrite sur le blog technique de Yahoo! sur le blog de Thierry. C’est de loin la plus complète, et la seule à ma connaissance à supporter la direction de texte de droite à gauche.
Mais elle n’est pas exempte de problème, désormais.
Propriété dépréciée
La « magie » de cette solution repose sur la propriété clip
. Elle est simple à comprendre et très efficace. Seul bémol : clip
est déprécié par le module CSS masking de niveau 1.
Pas de souci. La technique basée sur clip
date un peu, il est normal qu’elle tombe en désuétude. La nouvelle spécification recommande l’utilisation de clip-path
pour remplacer clip
. Ce qui nous laisse pantois, puisque le support de clip-path
est encore tout à fait relatif. Nous devons conserver clip
et ajouter clip-path
en guise d’amélioration progressive.
Cependant la syntaxe est différente également. Après quelques recherches, Yvain Liechti a proposé la version la plus courte pour obtenir le résultat attendu :
clip-path: inset(50%);
Banco. Un problème résolu !
Le texte ratatiné
J. Renée Beach a signalé que la propriété width: 1px;
avait des effets négatifs sur le rendu du texte et par conséquent sa vocalisation par un lecteur d’écran.
La solution proposée est à la fois logique et simple : empêcher le texte de passer à la ligne et ainsi garantir que les espaces entre les mots sont conservés.
Une seule propriété suffit :
white-space: nowrap;
Et voilà, second problème résolu.
La totale
Voilà la version finale que je propose actuellement :
.sr-only {
border: 0 !important;
clip: rect(1px, 1px, 1px, 1px) !important;
-webkit-clip-path: inset(50%) !important;
clip-path: inset(50%) !important;
height: 1px !important;
margin: -1px !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important;
white-space: nowrap !important;
}
Avertissement
Normalement, vous ne devriez utiliser ceci que pour du texte. Autrement dit, il ne devrait jamais y avoir d’élément capable de recevoir le :focus
dans un élément masqué de la sorte. Cela pourrait conduire à des comportements étonnants, puisque le navigateur cherchera à positionner le scroll à l’endroit où est placé le :focus
.
Cependant, si l’élément masqué peut lui-même recevoir le :focus
, il nous faut pouvoir l’afficher de nouveau. C’est généralement le cas pour les liens d’évitement. Lisez la technique G1 des WCAG pour en savoir plus.
Pour ce genre de cas, Bootstrap propose une classe supplémentaire pour remettre à zéro nos valeurs de masquage.
C’est à mon avis la meilleure façon de faire — et étant donné les changements apportés sur la classe de masquage, cette seconde classe doit être revue elle aussi. Voici ma version :
.sr-only-focusable:focus,
.sr-only-focusable:active {
clip: auto !important;
-webkit-clip-path: none !important;
clip-path: none !important;
height: auto !important;
margin: auto !important;
overflow: visible !important;
width: auto !important;
white-space: normal !important;
}
Code et traduction
Vous pouvez retrouver ces classes à plusieurs endroits :
Qu’en dites-vous ?
Version anglaise
Kitty Giraudel m’a fait l’honneur de traduire cet article en anglais et le publier sur son blog. Merci !
Modifications
Les lecteurs d’écran sur mobile
19 octobre 2016
Ayant besoin de tests sur cette version pour vérifier qu’elle n’introduit pas de régressions, Johan Ramon m’a remonté un bug étrange sur VoiceOver. En creusant un peu avec Sylvain Pigeard, il nous est apparu que position: static
posait problème lors de la prise de focus d’un lien ayant la classe .sr-only-focusable
.
Nous étions contents, lorsqu’en cherchant à avertir l’équipe de Bootstrap nous sommes tombés sur un ticket ouvert récemment qui implique également TalkBack. Patrick H. Lauke, en investiguant, a décelé de nombreuses incohérences dans la gestion du focus entre les diverses technologies d’assistance sur mobile. Il a ainsi ouvert des tickets un peu partout :
- Narrator, le lecteur d’écran intégré à Windows 8, Windows 10 et Windows Phone ;
- TalkBack, le lecteur d’écran intégré à Android, interfacé avec Chromium ;
- Firefox, qui tend à s’interfacer le mieux possible avec tous les lecteurs d’écran ;
- Webkit, le moteur de rendu de Safari ;
- Webkit, encore.
L’état des lieux est assez sombre : les liens d’évitement ne marchent globalement pas sur les interfaces tactiles lorsqu’on utilise un lecteur d’écran. Ô joie.
Le référencement naturel
19 octobre 2016
Steve Faulkner — du Paciello Group — a posé la question au forum de support pour webmasters de Google : les contextes supplémentaires pour utilisateurs malvoyants ont-ils un effet négatif sur le positionnement dans les résultats de recherche ?
Réponse courte : non Cependant étant donné que ce texte n’apparaît pas de prime abord il est considéré comme du contenu secondaire et a donc un très faible impact sur le positionnement, et c’est une excellente chose puisque cela dissuade d’en abuser.
Les débordements inopinés
18 janvier 2019
De multiples problèmes de débordements ont été observés, notamment sur Chrome, lorsque les éléments masqués sont contenus dans un élément avec overflow: auto;
. Le problème est résolu dans Boosted en ajoutant margin: -1px;
.
Super, tellement content d’être cité.
Il faudrait avoir un petit benchmark du comportement des différentes solutions de dictée d’écrans et navigateurs pour voir si la solution est bien universelle et bulletproof.
Parfaitement d’accord avec toi pour le benchmark, mais je n’ai pour le moment ni les moyens ni le temps de m’en occuper. C’est effectivement primordial, la découverte de J. Renée Beach illustre bien que cette technique n’a jamais été suffisamment éprouvée…
Et c’est normal pour la citation, c’est toi qui a cherché et trouvé le truc 🙂 Merci !
J’ai eu un problème cocasse avec ce genre de classe dans un cas bien précis, je tente de l’expliquer clairement :
– imagine avoir une loooooongue liste d’éléments avec des checkboxes masquées ainsi (pour des checkboxes personnalisées graphiquement mais qui restent accessibles)
– imagine ensuite que ces looooongues listes soient prises dans des hide/show (collapsible regions)
Rien d’extraordinaire à priori, mais sur certains navigateurs (Safari en tête), ça donnait un effet curieux. Quand tu cochais certaines de ces checkboxes, le navigateur scrollait aléatoirement dans la page. Sans raison, en mode WTF complet.
Voici l’explication : en fait, comme elles sont positionnées en absolu (et donc sorties du flux), et que le script de hide/show passe après, les checkboxes cachées ainsi se positionnaient dans la page (avec les hide/show ouverts) et restaient à leur place (et ce alors que le hide-show va repositionner des contenus).
Ce qui revient peu ou prou à ce qu’elles soient en bas de page ou positionnées n’importe comment. Du coup, quand tu en coches une, le navigateur met le focus sur la checkbox et ça donne ce WTF bizarre.
Donc, dans la plupart des cas, ça roule, mais gare au position: absolute qui fait des étrangetés parfois 🙂
Oups, j’ai oublié de mettre la parade : dans ces cas foireux, virer le position: absolute et vive opacity: 0 ou une bricole du genre 🙂
Pour mémo, la technique que j’utilise pour Röcssti est proche : https://github.com/nico3333fr/ROCSSTI/blob/master/src/css/rocssti-fr.css#L637
Pourquoi Important?
Bonjour Michel,
J’utilise systématiquement
!important
sur les classes utilitaires qui ont vocation à figer une propriété, ce qui est le cas ici. L’objectif étant que même incorporé dans un environnement sauvage (plusieurs bibliothèques de styles, des styles supplémentaires rédigés à la main par un débutant, etc.) ces styles soient appliqués. Vous utilisez cette classe pour masquer visuellement un élément’: si cela n’est plus le cas, retirez la classe au lieu de surcharger le style.Si d’aventure la personne qui intervient est tentée de retirer le
!important
— ou d’en ajouter pour le surcharger — elle commet une erreur : c’est la classe sur l’élément HTML qu’elle devrait retirer.Harry Roberts a écrit un article intéressant sur ce sujet, dans lequel il parle d’immuabilité.
C’est de l’ordre du choix, évidemment rien ne vous oblige à les conserver si cela va à l’encontre de vos pratiques.
Hello Gaël !
Article super complet, merci pour le partage.
Petit mot pour te dire que le lien vers le blog technique de Yahoo ne fonctionne plus. Vive la pérennité du web :’(
Bises !
Thomas.
Génial!
Je viens de faire une passe sur tous mes projets en cours, pour créer un ticket et demander une optim de la CSS de masquage 🙂
Et sinon, oui, il y a des motifs légitimes d’utilisation de texte caché, je trouve. Par exemple, avec les fontes-icones.
Un grand merci!
.sr-only et .sr-only-focusable deviennent .visually-hidden et .visually-hidden-focusable (et ne sont plus cumulables) : https://getbootstrap.com/docs/5.0/getting-started/accessibility/#visually-hidden-content