Edit : Updated the snippet with the margin property to overcome issues related to containing overflow.

Edit : Updated the article to mention some important information about screen-readers on mobile devices. as well as search engine optimisation.

This article is a translation from Cache-cache CSS by accessibility expert Gaël Poupard. All credits to him.

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.

Deprecated property

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:

clip-path: inset(50%);

Problem solved.

Shrinked text

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:

white-space: nowrap;

Problem solved again.

Wrapping things up

Here is the final version I came up with:

.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;
  overflow: hidden !important;
  margin: -1px !important;
  padding: 0 !important;
  position: absolute !important;
  width: 1px !important;
  white-space: nowrap !important;
}

Warning

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.

Bootstrap and HTML5 Boilerplate have a pretty good solution for this: another class meant to reset these properties.

Here is the adapted version:

.sr-only-focusable:focus,
.sr-only-focusable:active {
  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

You can find it on CodePen or in this Gist. What do you think?

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.

SEO (19/10/2016)

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.

margin: -1px;

Read previous post: 2016 in review

Read next post: You might need JavaScript