See No Evil: Hidden Content and Accessibility


When I first started learning web development I thought hiding content was simple: slap display: none; onto your hidden element and call it a day. Since then I’ve learned about screen readers, ARIA attributes, the HTML5 hidden attribute, and more!

It’s important to ensure our websites are accessible to everyone, regardless of whether or not they use a screen reader, but with this myriad of options, how do we know when to use what?

There are four main scenarios where you may wish to hide content: 1. Hiding content for everyone, regardless of whether they use a screen reader 2. Hiding content for screen readers while showing it to other users 3. Showing additional content for screen readers while hiding it from other users

4. Hiding content at specific screen sizes

Let’s dive deeper into each of those scenarios to learn how to handle them.

When hiding content for all users we can take advantage of HTML5’s hidden attribute. The hidden attribute signals that content should not be rendered, regardless of medium or screen reader use. In supported browsers it also hides the content from view, similar to display: none;.

It may feel odd to be handling display in your HTML instead of your CSS, but there’s a good reason for it! All devices should respect the hidden attribute, including browsers, screen readers, and printers, even if they don’t load your stylesheets.

This technique is most often used when a site is dynamically showing and hiding content, like a popup or accordion. You may need to combine the hidden attribute with a CSS class to allow for transitions. In that case, just make sure you update the hidden attribute whenever you change visibility by another means.

There’s one extra wrinkle when using hidden. It’s not supported in Internet Explorer 10 and below so if you do use hidden you should also set display: none; !important1 in CSS to ensure the content is hidden in all browsers.

<div class="example" hidden></div> <style> .example[hidden]{ display:none !important; }
</style>

This can also be set as a global style using attribute selectors.2

[hidden] { display: none !important;
}

Some content is not important for understanding a web page, but is added to make the design more visually appealing. For example, icons and glyphs can provide a nice visual polish, but tend to be unhelpful — and sometimes downright distracting — for screen reader users. In this scenario we’ll want to hide the content from screen readers while showing it to everyone else.

In this case we’ll use the aria-hidden attribute. aria-hidden is a boolean attribute so it can be set to true or false. Setting the attribute to false is the same as not including it at all, so you’ll generally want to set it to true and use it like this:

<div class="my-glyph" aria-hidden="true"></div>

aria-hidden="true" should not be confused with role="presentation" which strips the semantic meaning of an element from the accessibility tree. Here’s a helpful article outlining the difference between the two.

A good web page design often uses visual clues to convey information to the viewer. It’s important to structure your page so that screen reader users get these same clues from your text. For example, pagination may be obvious when laid out visually, but might read as a meaningless list of numbers over a screen reader. In these scenarios it’s helpful to include extra information for screen readers without cluttering up your visual design.

Setting display: none; hides the content but also removes it from the accessibility tree so screen readers won’t read it. Because of that it’s best to fall back to other CSS tools to hide the content while keeping it in the accessibility tree.

The 18f site has a great solution to hide content visually while keeping it in the accessibility tree for screen readers:

.sr-only { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px;
}

In the comments of this post Edward Martin pointed out that the CSS clip property is deprecated and that we should be using clip-path. clip-path isn’t fully supported yet, so for now it’s best to include both clip and clip-path.

In addition, Kimblim pointed out that this technique can cause screen readers to skip the spaces in between words and suggested adding white-space: nowrap; to avoid this.

Following this advice leaves us with this more robust class:

.sr-only { border: 0; clip: rect(0 0 0 0); clip-path: polygon(0px 0px, 0px 0px, 0px 0px); -webkit-clip-path: polygon(0px 0px, 0px 0px, 0px 0px); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; white-space: nowrap;
}

The aria-label attribute can also be used to provide additional information to screen readers though generally the CSS solution is preferable. It’s worth learning both techniques and knowing when to use one or the other.

When building responsive web pages designers often choose to display content at certain screen sizes but not others using media queries. In these scenarios the content should generally be included in the accessibility tree for screen readers, so hidden and aria-hidden are not necessary.3

Now we’ve got a lot of tools in our toolbox. We can hide content for all users, for screen readers, for users not using screen readers, and for specific screen sizes. Learning how to properly hide content in an accessible way is a valuable skill for anyone touching the front-end, and your users will appreciate it!