Accessible display: none

Note: This post is outdated. Instead, read this article: Now You See Me.

From time to time, the necessity arises to have hidden content present in a page. In case you don't already know, simply using CSS for display: none on the content will not cut it, because assistive technologies such as screen readers will treat this content as if it does not even exist in the DOM.

Many show/hide methods will allow the XHTML content to load, pre-hiding it via JavaScript using display: none and then re-showing it with display: block. This is a perfectly good method, and is accessible. I myself do hide/show elements this way, using Peter-Paul Koch's proposed usage of document.write(). You can read about it at his site, Quirksmode.

Yet, what do we do about those fringe cases in which content needs to be present in a page, yet hidden with no intention of re-showing it dynamically? Obviously, if you are not going to be manipulating the element via DOM scripting, then it shouldn't be used to hide said content in the first place. We could use absolute positioning, but that gets tricky if you are also doing multiple layers of complex z-index transparency within a design.

Example

A search form would be the quintessential example of where you would want an element hidden, while still leaving it accessible to screen readers. While most search forms are easy enough to recognize to those who are sighted, far too many lack the required <label for="x">Search</label> paired with an input. Without this, screen readers cannot associate the text field with its description, leaving blind users to inferences based on conjecture.

Consider the following demonstration. First off, we have the styled search form, with the label tag viewable. Below is the form's code, in XHTML 1.0 Strict. Note, the span is there for styling ala Shaun Inman's method.

<form method="get" action="#" id="search_form">
<input type="hidden" name="phpMyAdmin" value="7f5f0aec2286bb95a2290f59f32bfc82" />
<p>
<label for="q">Search</label>
<span>
<input type="text" name="q" id="q" />
</span>
<input
type="image"
src="/img/search.gif?phpMyAdmin=7f5f0aec2286bb95a2290f59f32bfc82"
alt="Search"
/>

</p>
</form>

With no additional styling applied to the label, we get a the following visual output, with Search displayed in black at the default 16px sized serif font.

label - default

With visibility: hidden we have a conspicuously ugly space left behind.

label - visibility: hidden

However, by using some clever CSS we can achieve the same visual effect as display: none without the accessibility drawbacks. By doing it this way, we get the best of both worlds: lack of visual redundancy, while still being nice to blind users. This method is also search engine friendly, in case you are worried about Google rumors. Ideally, this is how we want it to look.

label - concealed

The code for this is really quite simple. By default, the label tag is an inline element, meaning that we are unable to style its dimensions. In order to wrangle it under control, we do something that might be considered counter-intuitive. We give it display: block so that we can set its dimensions, and then we use overflow: hidden to cull its contents.

#search_form label {
display: block;
overflow: hidden;
width: 0;
height: 0;
}

I like to think of this method as fixing a piece of fabric when a thread is hanging loose. Just grab the other end of the strand and then pull it back through the cloth - Nobody is the wiser that it ever protruded.


Update:

According to accessibility expert James Edwards, the screen reader Window Eyes has problems reading content that is contained in elements with 0 dimensions and overflow: hidden. I personally still prefer this method to others out there, but wanted to make readers aware of the potential drawbacks regarding this particular assistive technology.

At the request of accessibility expert Derek Featherstone, I have uploaded a test example here:

display-test.html