Improved .visually-hidden
Theorically bulletproof CSS class for visually hide anything and keep it accessible to ATs.
<button type="button"> | |
<span aria-hidden="true">×</span> | |
<span class="visually-hidden">Close</span> | |
</button> | |
<a href="/" class="visually-hidden-focusable">Skippy</a> | |
<div dir="rtl"> | |
<button type="button"> | |
<span aria-hidden="true">×</span> | |
<span class="visually-hidden">Close</span> | |
</button> | |
<a href="ffoodd.fr" class="visually-hidden-focusable">ffoodd.fr</a> | |
</div> |
/* | |
Improved screen reader only CSS class | |
@author Gaël Poupard | |
@note Based on Yahoo!'s technique | |
@author Thierry Koblentz | |
@see https://www.cssmojo.com/hide-content-from-sighted-users/ | |
* 1. | |
@note Use to only display content when it's focused, or one of its child elements is focused | |
@see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 | |
@note Based on a HTML5 Boilerplate technique, included in Bootstrap | |
* 2. | |
@note `clip-path` shortest syntax | |
@author Yvain Liechti | |
@see https://twitter.com/ryuran78/status/778943389819604992 | |
* 3. | |
@note preventing text to be condensed | |
author J. Renée Beach | |
@see https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe | |
@note Drupal 8 goes with word-wrap: normal instead | |
@see https://www.drupal.org/node/2045151 | |
@see http://cgit.drupalcode.org/drupal/commit/?id=5b847ea | |
* 4. | |
@note !important is important | |
@note Obviously you wanna hide something | |
@author Harry Roberts | |
@see https://csswizardry.com/2016/05/the-importance-of-important/ | |
*/ | |
.visually-hidden, | |
.visually-hidden-focusable:not(:focus, :focus-within) { | |
border: 0 !important; | |
clip-path: inset(50%) !important; /* 2 */ | |
height: 1px !important; | |
margin: -1px !important; | |
overflow: hidden !important; | |
padding: 0 !important; | |
width: 1px !important; | |
white-space: nowrap !important; /* 3 */ | |
} | |
/* | |
Prevent visually hidden caption from breaking table's collapsing borders | |
@author Louis-Maxime Piton | |
@see https://github.com/twbs/bootstrap/pull/37533 | |
*/ | |
.visually-hidden:not(caption), | |
.visually-hidden-focusable:not(caption):not(:focus, :focus-within) { | |
position: absolute !important; | |
} | |
/* | |
Prevent overflowing children from being focusable. | |
@author Django Janny | |
@see https://github.com/twbs/bootstrap/pull/41286 | |
*/ | |
.visually-hidden *, | |
.visually-hidden-focusable:not(:focus, :focus-within) * { | |
overflow: hidden !important; | |
} |
It would indeed, but won't:
There might be more arguments, but you got the picture: I really think visually hidden content is better than ARIA attributes — and it also better respects ARIA rules, since we can use HTML & CSS to do this.
Thank you so much for this. You may want to change the first see link (in the css) to an archive.org copy as the original is no longer available.
Thanks @GlitzSmarter for reporting, I managed to find a copy on the author's own blog.
Why position absolute as opposed to fixed?
Why position absolute as opposed to fixed?
@aquaductape https://webaim.org/techniques/css/invisiblecontent/
"position:absolute; tells the browser to remove the element from the page flow and to begin positioning it."
Why position absolute as opposed to fixed?
@aquaductape https://webaim.org/techniques/css/invisiblecontent/ "position:absolute; tells the browser to remove the element from the page flow and to begin positioning it."
position: fixed;
would also do that :
The element is removed from the normal document flow, and no space is created for the element in the page layout.
In this case, position: absolute;
is (very marginally) better because the element will then be positioned closer to the place it is used in the page. Given that screen readers are used not only by blind users, but users with vision deficiencies more broadly, some users could jump to a visually hidden element. The page wouldn't then scroll because the fixed element is positioned relative to the viewport.
This is a corner case since it would be problematic only with element containing only visually hidden elements.
I recently came across a strange behavior with sr-only
.
When an element inside the sr-only
element becomes scrollable due to the sr-only
, it is also focusable and the focus feels lost... Took me a while to figure it out though...
Here is a simple codepen to try it and an attempt to fix it (overflow: hidden to all children).
What do you think @ffoodd ?
Hi @keltroth. What's your use case to put a scrollable content into the sr-only area? I cannot imagine a case where that would be correct. Definitely not with .sr-only
which is also applied to a focused element or an element with focus within like the code in this thread. (I actually always implement this class in a way that it's not applied to a focused element or element with focus within as there is no case where that would be correct. Focused element must be always visible to the user.)
Also, scrollable regions should be ideally always focusable (unless you are certain that there always is a focusable element inside it, but ideally even in such case). We're usually doing this manually via setting tabindex="0" to that element, often combined with some role like role="region". Read these resources to understand why:
Thanks to your post, I found out that some browsers actually started making scrollable regions scrollable automatically. As this is crucial for keyboard users (see the links above for explanation), this is something you have to respect. Read this article where this feature is mentioned:
https://cassey.dev/til/2019-11-19-overflow-scroll-gets-focus/
To sum it up, your use case or intention is most likely not OK. Please provide more information to help us guide you to find a correct solution for your case.
@keltroth If I sum this case up, since scrollable elements become focusable, any child in . sr-only
that'd become scrollable will also become focusable.
I can't see any other workaround than yours, for now.
FWIW, as @thiemeljiri said, .sr-only
is usually used on text-level elements. Hiding complex content this way should be avoided.
I came to the same conclusion. Thanks !
Are the better examples because it doesn’t fit in the use of a button since a button can handle the same thing using
aria-label
Pretty sure the
aria-label
will override the text content of a button for screen readers. 🤔