Edit : Updated the snippet with the margin property to overcome issues related to containing overflow.
Or how to visually hide some text while keeping it accessible.
And even if I find this stupid—hiding text from some users but not others seems inherently wrong from an accessibility stand point to me—it’s a recurring need.
There are many ways of doing this, that I won’t detail here. For the past few years, I’ve been using this technique from Thierry Koblentz described on his blog. It’s by far the most comprehensive, and—to my knowledge—the only way supporting RTL text orientation.
Unfortunately it’s not without issue anymore.
The “magic trick” of this solution relies on the
clip property. It’s simple to understand and very efficient. Only downside:
clip has been deprecated by the CSS Masking Level 1 module.
No worries. This technique being quite old now, there is no surprise it’s getting obsolete. The new specification recommends using
clip-path to replace
clip. Which is not ideal, because
clip-path support is still so-so. Thus we have to keep
clip and add
clip-path as progressive enhancement.
That being said, the syntax is different. After a bit of research, Yvain Liechti suggested this short version to get the expected result:
J. Renée Beach warned about the
width: 1px declaration having side effects on text rendering and therefore on its vocalisation by screen readers.
The suggested solution is both simple and logical: preventing the text from wrapping so that spaces between words are preserved.
Only one declaration does that:
Problem solved again.
Wrapping things up
Here is the final version I came up with:
border: 0 !important;
clip: rect(1px, 1px, 1px, 1px) !important;
-webkit-clip-path: inset(50%) !important;
clip-path: inset(50%) !important;
height: 1px !important;
overflow: hidden !important;
margin: -1px !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important;
white-space: nowrap !important;
This technique should only be used to mask text. In other words, there shouldn’t be any focusable element inside the hidden element. This could lead to annoying behaviours, like scrolling to an invisible element.
That being said, you may want to hide a focusable element itself; a common candidate are skip links (a WCAG 2.0 technique). Most of the time we hide them until they get the focus.
Here is the adapted version:
clip: auto !important;
-webkit-clip-path: none !important;
clip-path: none !important;
height: auto !important;
overflow: visible !important;
width: auto !important;
white-space: normal !important;
Go for it
Screen readers and touch devices (19/10/2016)
Seeking some testers to make sure I didn’t cause any regression, Johan Ramon met a strange bug with VoiceOver. Digging further with Sylvain Pigeard, we found out that
position: static is buggy on iOS 10 + VO when
.sr-only-focusable is focused.
As we thought we discovered a real bug, I headed up to Bootstrap in order to open an issue. But it came out that an issue was already opened, involving TalkBack too. I shared our result to contribute, then Patrick H. Lauke did an awesome (and still in progress) work to determinate and describe precisely the problem. As a result, he filled many bugs:
- Narrator, included in Windows 10 and Windows Phone;
- Chromium, impacting TalkBack on Android;
- Firefox — this one was already opened, but also by Patrick Lauke recently;
- and finally, two bugs for Webkit, impacting VoiceOver.
So. In fact, skip links don’t work with screen readers on touch devices at the time of writing. Nice.
Steve Faulkner from the Paciello Group asked to the Google Webmaster Central Help Forum directly if extra context for vision impaired users has a negative effect on search ranking?.
Short answer: nope. However visually hidden content are considered secondary, in order to prevent abuses. And that’s great.
Undesirable overflows (18/01/2019)
Multiple overflow-related issues were noticed, particularly on Chrome, when hidden elements live within a parent with
overflow: auto. The problem was addressed in Orange’s Boosted framework by adding
margin: -1px to the ruleset.