Hiding Content for Accessibility

For years now, we've used a number of techniques for hiding content offscreen for accessibility purposes. We do this because the content is still accessible to screenreaders while being removed from the interface for sighted users.

An article over at Adaptive Themes reviews a number of techniques for hiding content that were considered for inclusion on a Drupal 7 project (but certainly applicable to any project).

Here is a summary of those techniques and the pitfalls of each technique:

Text Indent

.element-invisible {
text-indent: -9999em;
outline: 0;
}

Unfortunately, this technique doesn't work with RTL (Right-to-Left) languages.

Position Absolute and Collapsed

.element-invisible {
height: 0;
overflow: hidden;
position: absolute;
}

In this case, Apple's Voice Over will not read content within an element that has zero height.

Position Absolute and Offscreen

.element-invisible {
position: absolute;
top: -999999em;
left: auto;
width: 1px;
height: 1px;
overflow:hidden;
}

In this case, if you have focusable content within the positioned element, the page will scroll to that element, thus creating an unsettling jump for sighted users.

Clip Method

.element-invisible {
position: absolute !important;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
}

The article ends with this final technique and is the solution they ended up using on their project.

With the work I've been doing at Yahoo!, we had been using the Position Absolute and Offscreen method. But sometimes we wanted to set focus to offscreen content. We had switched our technique to the Clip Method but uncovered differing behaviour between browsers.

Everything works great in Internet Explorer and Firefox. However, in Webkit (Chrome and Safari) and Opera, there's an interesting behavior when the element is at the edge of the screen. If the element, when unclipped, is large enough to force a horizontal scrollbar, will force a scrollbar even when clipped.

This seems to go against the CSS 2.1 guidelines that say:

Content that has been clipped does not cause overflow.

However, by forcing a scrollbar in Webkit and Opera, it does, in fact, seem to cause overflow. So how did we get around this?

Positioned, Clipped, and (almost) Collapsed

We combine a few techniques into one:

.element-invisible {
position: absolute !important;
height: 1px; width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
}

Using absolute positioning, we take the element out of flow so as not to affect the layout of anything around it. With a height of 1px, the element should still be visible for Voice Over to read the content. The clipping removes any visible trace of the element from the page.

Any focusable elements inside are still focusable, so depending on placement within the overall layout, some considered placement may still be of concern. Although, I might question why you are focusing on an element that was so far removed from the overall flow of the document.

We've only begun using and testing this technique, so even this may not be perfect. Any feedback and suggestions are quite welcome.