Beware smushed off-screen accessible text

My colleague, Matt King, encounters a lot of friction when using web UIs. Matt uses a screen reader to access the web. A screen reader expresses through speech and sound the text and controls of an interface. He and I work together on the accessibility team at Facebook. Whenever we are collaborating together, we inevitably find little gotchas. Over a few sessions, Matt mentioned that the string of text “Show more reactions” was being smushed together and read as “Showmorereactions”. 
 
This is something Matt had noticed before, but it had never been so obvious. For example, the two phrases “News Feed” and “NewsFeed” sound very similar when read aloud. I checked the HTML for the element on my computer and found that the words had spaces between them. We then wondered if the folks who developed this feature had used a character that looks like whitespace, but really isn’t — some exotic HTML entity or something. But the source code revealed normal space. I accessed the node’s text content through the DOM and the resulting string had spaces. As far as I could determined, the spaces between “show”, “more” and “reactions” were there right up to the moment that Matt heard them pronounced by the screen reader.
 
The one detail you need to know about this UI element is that it is not visible on the screen. We use a technique known as “invisible content”. It’s documented here on the Web AIM site: http://webaim.org/techniques/css/invisiblecontent/
 
Basically, the technique smushes, clips, de-flows and hides content so that it is only perceptible to assistive technology like a screen reader. Our implementation looked like this:

.accessible_elem {
clip: rect(1px 1px 1px 1px); /* IE 6/7 */
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}

I had a hunch that this little class was the source of the bad behavior. I removed it from the element and asked Matt to test. A moment later he declared it fixed! Next I put the class back and started removing properties one by one to see which one was the root of the issue: clip, overflow, position, height…width. I pulled out the width property and the spaces were present again.
 
Matt and I puzzled over why when a nearby colleague, Brett Lavalla, who had been listening to us debug this issue, offered a suggestion. Try white-space nowrap.

white-space: nowrap;

He guessed that the zero-width element forced the content to wrap to one word per line. When the screen reader pulled the content of the element to announce it, it received something like:

"ShowLFMoreLFReactions"

Where “LF” stands for line feed. The line feeds are not interpreted as spaces, so the phrase gets smushed into one long word. The white-space property forces the content to render on one line. We add this one-line change to our accessible text utility class.

.accessible_elem {
clip: rect(1px 1px 1px 1px); /* IE 6/7 */
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap; /* added line */
width: 1px;
}

This is a good example of polish in accessible user interfaces. Was the interaction usable before? Yes, even though the interaction could be difficult and annoying depending on the smushed phrase. In the same way we’re constantly looking to adjust colors, alignment and sizing of our visual UIs to make them more usable, we should always be looking for ways to polish our aural (spoken) UIs to the same levels of quality.