JavaScript and Screen Readers

Tweet

The following is republished from the Tech Times #163.

Try to use one of the poster-child Ajax web applications like GMail with a screen reader and you’ll never want to touch a screen reader again. To support those users who don’t have that luxury, then, do you have to do without JavaScript?

The answer to this question ultimately depends on the sort of web application you need to build. Of course, if you’re developing something as silly as a web-based version of Photoshop, you can probably rule out screen reader support at the outset.

Most web applications, however, will fall into a gray area where it’s possible to support screen readers—even without sacrificing any of the JavaScripty goodness you want to deliver to the rest of your user base. The question then becomes, is it practical?

A Practical Example

Setting aside the likes of GMail for the moment, let’s look again at the accordion control that’s built as an example in my upcoming book.

A couple of issues back, we modified this example to make it accessible to keyboard users. All we had to do was include a hyperlink in the heading of each section of the accordion so that it would be keyboard-focusable. As we’ll see, making this construct accessible to screen reader users is equally straightforward—it’s doing both at once that’s a little tricky!

To refresh your memory, here’s what the HTML code for this page looks like:

<ul class="accordion">
  <li id="archer">
    <h2><a href="#archer">Jonathan Archer</a></h2>
    <p>Vessel registry: NX-01</p>
    <p>Assumed command: 2151</p>
    ...
  </li>
  ...
</ul>

If that’s all there were to this page, it would be perfectly accessible to screen readers. We only get into trouble when our JavaScript code hides portions of the page content by dynamically setting a class of "collapsed" on the list items that make up the accordion. This class hides all but the heading inside the list item:

li.collapsed * {
  display: none;
}
li.collapsed h2,
li.collapsed h2 a:link, li.collapsed h2 a:visited {
  display: block;
}

The problem here is that using display: none to hide an element from view also hides the element from screen readers, and screen reader users are unable to read that portion of the page.

Of course, this might not be an issue if revealing the elements by switching off the "collapsed" property also revealed those elements to screen reader users. Were that the case, screen reader users could use the accordion just as other users do: by “clicking” a header in the accordion to reveal its contents.

As it turns out, however, this is not always the case. Most screen readers work with a static copy of the page’s visible contents—a copy that is infrequently and unpredictably updated (despite early signs from some vendors that this may be changing). And even in screen readers that do refresh their copy of the page contents in response to the user clicking a link, making the user aware that the content has been revealed is problematic at best.

No, your best bet in this case is to hide the contents of the collapsed accordion in such a way that screen reader users are still able to read them. The most useful technique to do this is called offleft positioning, and the CSS code looks like this:

li.collapsed * {
  position: absolute;
  left: -9999px;
}

li.collapsed h2,
li.collapsed h2 a:link, li.collapsed h2 a:visited {
  position: static;
}

In essence, this technique hides elements of the page by positioning them off the left of the page (9999 pixels off the left of the page, to be precise), where they will still be visible to screen readers.

So now screen reader users can read the entire content of the page without any interference from our JavaScript-driven accordion effects! Problem solved, right?

Well, not quite. You see, offleft positioning not only reveals the hidden elements to screen readers—it makes them available to keyboard users as well! In this case, when a keyboard user taps the Tab key to step through the focusable elements in the page, the focus will also step through any hyperlinks in our hidden content. Since these elements are invisible, the keyboard focus will seem to disappear, leading to angry phone calls.

Since there’s no reliable way to hide elements from keyboard users without also hiding them from screen reader users, we need to take a different approach. How about we do something useful when keyboard focus is given to a hidden element … like expanding the relevant section of the accordion!

We can add to every focusable element within the accordion (except, of course, the links in the always-visible headers) a focus event listener:

var folds = accordion.getElementsByTagName("li");
for (var i = 0; i < folds.length; i++)
{
  var foldLinks = folds[i].getElementsByTagName("a");
  var foldTitleLink = foldLinks[0];
  addEvent(foldTitleLink, "click", Accordion.clickListener);

  for (var j = 1; j < foldLinks.length; j++)
  {
    addEvent(foldLinks[j], "focus", Accordion.focusListener);
  }

}

When triggered, that focusListener function will expand the section of the accordion that contains it:

focusListener: function(event)
{
  var element = this;
  while (element.parentNode)
  {
    if (element.parentNode.className == "accordion")
    {
      Accordion.expand(element);
      return;
    }
    element = element.parentNode;
  }
}

And there you have it—an accordion control that is accessible to both keyboard and screen reader users!

More Complex Cases

As you might expect, not all JavaScript enhancements can be adapted to avoid interference with screen readers and keyboard navigation. Sometimes, the best you can do is make it easier for these users to disable the stuff that won’t work for them.

In a recent blog post, for example, Jeremy Keith applauds Dan Champion‘s new social book review site, Revish, which offers users the option of disabling the Ajax features of the site that won’t work with screen readers when they sign up for an account. This solution is nice and slick, allows the user to feel in control, and is extremely easy to implement, too!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • ChestRockwell

    Good article, you know, setting a height to 0 and overflow: hidden also works very well for the whole hide-and-read problem too. Also, I don’t know if turning AJAX features on or off is a good way of handling things. The company I work for is redeveloping a website for the blind, and the blind users are really against the idea of 2 different websites and turning features off. They really just want a site that works regardless of the user or his/her disability. Turing things off makes them feel different and singled out. It says to them, that you didn’t take the time to think of a solution, you just went and made a different site, which to them, isn’t a solution, its laziness.

  • http://www.sitepoint.com/ Kevin Yank

    Chest,

    I definitely agree with you.

    To clarify, when I suggest giving screen reader users a way to “disable the stuff that won’t work for them,” I mean enabling them to switch off the JavaScript enhancements so that they can access the functionality without JavaScript. Building your JavaScript enhancenets atop working non-JavaScript functionality will ensure that screen reader users, and other users that can’t take advantage of your JavaScripty goodness, will still be able to access all of your site’s functionality.

  • what

    what’s a screen read? for a first time read, your writing makes little sense if any… not once do you make mention of what a screen reader is….

  • http://www.sitepoint.com/ Kevin Yank

    Sorry about that, what. A screen reader is a software application used by visually impaired users (as well as people with some cognitive disabilities) that reads the content of a web page aloud.

  • momos

    I’m guessing most people reading this know what a screen reader is though, and if not then you can still look it up (google/wikipedia)

  • http://www.eclecticdreams.com Matt_Machell

    Chest,

    I agree, screenreader users want to be included.

    Part of the problem is the phrasing though, too often the wording makes users feel like they’re being short changed. Rather than making it a negative “turn X off” phrasing, it’s better surely to phrase as a positive “turn on enhanced screenreader support”. Because if you’re doing things well, the options are still there, just in an easier to use form for those using AT.

  • Ran

    Look into the built-in support for screen readers available in Bindows (www.bindows.net) – a commercial Ajax development platform.
    Their site includes demos and (tests with screen readers) of Ajax applications (that look and feel just like Windows) and are fully accessible to visually impaired (http://www.bindows.net/508/).

  • NMB

    This is just me, but I think I like Chest’s example of height:0/overflow:hidden better than -9999px. There was a time when Google penalized sites for moving content outside the viewport. People were doing this to hide non-relevant content from human users in an attempt to trick the search engines.

    I can also see the potential for some strange visuals on slower computers as the browser moves these elements in and out of the viewport.

    Good stuff Kevin… I’ve always enjoyed your practical approach.

    PS: I would also expect anyone reading this article (or even this website) to either know what a screen reader is or take some initiative and look it up. It would seem to be less work to enter 2 words into Google, than to post a question and wait for a response. Yes, Kevin probably should have addressed that, but still…

  • http://www.brothercake.com/ brothercake

    If Google penalizes users for doing this, then Google is broken – period.

    The height:0;overflow:hidden; solution unfortunately recreates the same problem – Window Eyes cannot read content which is completely hidden with overflow (although content which is only partially hidden is fine)

  • http://www.dustindiaz.com polvero

    You know, Gmail comes in an alternate version that works with screen readers. So I doubt screen reader users are unlikely to use the Ajax version.

  • Yuccaplant

    I found this article somewhat confusing. I thought screenreaders refreshed the virtual buffer when there is an “onclick” event, at least the more modern screenreaders.

    I attended an accessibilty course, with the teacher being blind. He stated that’s not good practice to let feed blind users the full text, while visioned users could faster select the portions thay want read. All there is to do, is to put focus to the content that was made visible by javascript.

    I think this isan interesting article:

  • Lovemore Nalube

    Fellow programmers

    Using display: none DOES NOT hide the text/element from being read by screen readers! Actually, so far there doesn’t seem to be a sure way of hiding html text content from screen readers.

    A survey has been done (available on Bob Easton’s [Access Matters blog].) to evaluate the ability to hide elements from screen readers. It seems to be difficult things to accomplish (so far).

    Have a look at the survey!

  • Notsofast

    Following Lovemore Nalube’s suggestion, I read the results of Bob Easton’s survey, and I come to the opposite conclusion: Many browser/reader combinations fail to read text styled as display:none, regardless of whether the style is inline, in an embedded stylesheet, or in an imported stylesheet. The results are outdated, though. The latest version of IE tested was 6. (It’s interesting that IE 4 would read anything styled as display:none, but IE 5 and 6 would not.)