Issue № 327

Now You See Me

A note from the editors: We are delighted to present an excerpt of Aaron’s new book Adaptive Web Design.

Perhaps the most heavily-repeated pattern in JavaScript-based page manipulation is showing and hiding content. Tabbed interfaces. Collapsible elements. Accordion widgets. It crops up nearly everywhere. In and of itself, this pattern is not a bad thing, but few people realize how profoundly your choice of hiding mechanism can influence the accessibility of your content to assistive technologies like screen readers.

Article Continues Below

When building custom JavaScript-based widgets, it’s quite easy to fully control the hiding mechanism, but when you begin working with animation libraries like jQuery or Scriptaculous, the hiding mechanism is typically dictated by the library, leaving you little control over the accessibility of your content. And that’s a problem.

Peek-a-boo#section2

When it comes to hiding content, there are several mechanisms for doing it and each affects the page differently, as summarized in the table below:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Mechanisms for Hiding Content
CSS Rules Display Effect Accessibility Effect
visibility: hidden; Element is hidden from view, but is not removed from the normal flow (i.e., it still takes up the space it normally would) Content is ignored by screen readers
display: none; Element is removed from the normal flow and hidden; the space it occupied is collapsed Content is ignored by screen readers
height: 0; width: 0; overflow: hidden; Element is collapsed and contents are hidden Content is ignored by screen readers
text-indent: -999em; Contents are shifted off-screen and hidden from view, but links may “focus” oddly and negative indent may not prove long enough to fully hide content Screen readers have access to the content, but the content is limited to text and inline elements
position: absolute; left: -999em; Content is removed from the normal flow and shifted off the left-hand edge; the space it occupied is collapsed Screen readers have access to the content

The first two mechanisms are probably the most popular, with display: none; being the go-to option implemented by nearly every JavaScript library on the planet and the lion’s share of ready-made JavaScript widgets. If you don’t want your hidden content to be read by a screen reader, those defaults may work for you, but if you want to ensure users have access to content (even if it isn’t displayed visually in the current interface), the final option (positioning content offscreen) is really the way to go.

Note: the offscreen positioning assumes a left-to-right language page. For right-to-left, swap a right offset for the left one.

Hollaback scripts#section3

If you roll your own JavaScript library, positioning content off-screen to hide it is pretty easy to implement. If, however, you are using a third-party JavaScript library, such as jQuery or Prototype, this task becomes much more difficult to accomplish because making the change requires overwriting or otherwise changing the internals of the library. Unless, of course, you’re smart about how you do it.

Most libraries include, as part of their animation suite, a mechanism for including what are referred to as “callback functions.” A callback function is a function that you supply to another function (or object method) so that it can be called at a predetermined time. If you’ve used JavaScript to load content via Ajax, you’re probably familiar with the concept: callback functions are used to do something with the data you got back from the server.

In most cases, JavaScript libraries only offer a callback function that runs at the completion of a given activity, but some libraries also provide hooks for various other points during the execution of a given routine, such as before the routine begins. Even without additional callback hooks, however, it’s possible to create more accessible show/hide operations. Take the following jQuery-based snippet, for example:

(function(){
  var $button = $('#myButton'),
      $text   = $('#myText'),
      visible = true;
  $button.click(function(){
    if ( visible ) {
      $text.slideUp('fast');
    } else {
      $text.slideDown('fast');
    }
    visible = ! visible;
  });
})();

This script finds two elements (#myButton and #myText), assigning them to two local variables ($button and $text, respectively) before setting a third local variable (visible) to track the current state of things. It then goes on to assign an onclick event handler to #myButton that toggles the visibility of #myText by adjusting its height. Pretty straightforward, right?

This script works as you’d expect, but jQuery currently uses display: none when you call slideUp(), so #myText is being hidden via a method that prohibits the hidden text from being read by a screen reader. By making a subtle tweak to the code, however, we can trigger the addition of a class we control that provides for a more accessible means of hiding content:

(function(){
  var $button = $('#myButton'),
      $text   = $('#myText'),
      visible = true;
  $button.click(function(){
    if ( visible ) {
      $text.slideUp('fast',function(){
        $text.addClass('accessibly-hidden')
             .slideDown(0);
      });
    } else {
      $text.slideUp(0,function(){
        $text.removeClass('accessibly-hidden')
             .slideDown('fast');
      });
    }
    visible = ! visible;
  });
})();

This script is almost identical to the last one, in that when the content is being hidden, the library is allowed to manage the animation, but then the script swaps the default completion state for our custom class “accessibly-hidden,” thereby keeping the content available to assistive devices. When the script goes to show the content, the steps are reversed, with the content being hidden by the script again before the class is removed and the actual animation is performed.

The added benefit of this approach is that you control the method of hiding content completely, as opposed to leaving it up to the JavaScript library. That means you can upgrade your “accessibly-hidden” to use a different technique if something better comes along and you don’t have to wait for the library to upgrade its hiding mechanism (if it ever does).

JavaScript is a powerful tool for building rich interactions online. We already know that, when we do it, we need to be unobtrusive and build the behavior layer following progressive enhancement, but sometimes that only gets us so far. Thankfully, however, with a little thoughtful reflection, we can take our scripts that extra step and make our pages just a little more accessible.

38 Reader Comments

  1. I hadn’t realised that screen readers processed javascript at all. My method to date has been to ensure that everything is visible in terms of HTML/CSS, only using jQuery to hide elements on page load. Do all modern screen readers use javascript nowadays?

  2. I believe they do Garve but a large percentage of people still use something older.

  3. I was looking forward to this book, but after reading this excerpt I almost have no interest now.

    The proposed best solution in this day is to position things off screen ~999em’s ? This is not a line of thinking I wish to see furthered in any modern web builds. I’m no JS ninja, but I’m fairly certain one day soon we will gravely regret ever positioning objects off the viewable page into outer space. It’s an awful hack that I think developers should stopped using a while ago. Even though “display:none” has it’s screen-reader shortcomings, I can think of no better alternative at this time.

    Though, I will say the article was very well written and educational.

  4. When ‘accessibly-hidden’ is added via JQuery is it changing the state of display: none and adding text-indent and/or positioning CSS to achieve the same effect? Why is the slideDown(0) in the hiding portion of the code?

  5. Unlike the snark rovo, above, I eagerly await this book. Thanks for the snippet. I am encouraged that I may finally be able to follow direct and clear instructions to implement unobtrusive and accessible jQuery.

  6. This seems to me like a usable approach for SEO issues (what is hidden isn’t indexable) but I really do not see, what kind of assisting devices actually need to understand JavaScript.
    Would I program visual effects for blind people?

  7. bq. I hadn’t realised that screen readers processed javascript at all. My method to date has been to ensure that everything is visible in terms of HTML/CSS, only using jQuery to hide elements on page load. Do all modern screen readers use javascript nowadays?

    With the advent of WAI-ARIA and a greater understanding of accessibility, the accessibility community’s previous encouragement of assistive technology users to disable JavaScript has been reversed. We can now create very accessible interfaces that use JavaScript. It is even possible to use JavaScript to enhance the accessibility of a page beyond what is possible in markup alone (as Derek Featherstone & company have shown).

    For the record, it isn’t (at least in my experience) that assistive technologies “process” JavaScript, but they receive access to the markup, etc. via APIs provided by the browser.

    bq. This is not a line of thinking I wish to see furthered in any modern web builds.

    I agree it isn’t ideal, but offscreen positioning is the only reliable way to visually hide content without making it inaccessible to assistive technologies. Perhaps that will change in the future, but it’s what works best now.

    bq. When “˜accessibly-hidden’ is added via JQuery is it changing the state of display: none and adding text-indent and/or positioning CSS to achieve the same effect? Why is the slideDown(0) in the hiding portion of the code?

    The “accessibly-hidden” @class@ simply hides the content by positioning it off-screen. When jQuery applies that @class@, the content is hidden from view and the @slideUp@ (which originally hid the content by adjusting the element’s height before setting @display:none@) can be reversed (thereby removing the @display:none@ CSS property jQuery had applied). It’s kind of like sleight of hand.

    The steps are reversed when a user goes to expand the element again.

    bq. Excuse my ignorance but are these software readers or actual devices? if it’s hardware, are there emulators available?

    In some cases, they are software (such as screen readers like the excellent NVDA catchmyfame mentioned). In other cases, they are a hardware/software combination (e.g. a braille printer or touch-feedback device). I am not aware of emulators for hardware-based assistive technologies. I don’t think they’re often needed; most hardware-based assistive tech has a direct equivalency to more common input devices (e.g. mouse, keyboard, etc.) and output devices (e.g. printers, speakers, etc.).

    bq. This seems to me like a usable approach for SEO issues (what is hidden isn’t indexable) but I really do not see, what kind of assisting devices actually need to understand JavaScript.
    Would I program visual effects for blind people?

    If all you are using JavaScript for is visual effects, you’re only scratching the surface of its power. But, since you asked, it’s not that we are programming JavaScript specifically _for blind people_ (or any other people for that matter), but that we are programming _with *respect* to people_. We should strive to make our websites provide a great experience whether you have “special needs” because you’re blind or because you’re on a mobile device. A user’s situation is unknowable, but in order to provide them with an amazing experience, we need to be considerate of whatever their situation might be.

  8. Wouldn’t top: 100% (or left: 100%) work better than left with an arbitrary, obsolete-able static value, especially with overflow: hidden set on a parent element?

  9. Just wondering about the “newest” thinking on this topic. Here is what I am referring to:

    .accessibility {
    border: 0 none !important;
    clip: rect(0.1em, 0.1em, 0.1em, 0.1em);
    height: 0.1em !important;
    overflow: hidden;
    padding: 0 !important;
    position: absolute !important;
    width: 0.1em !important;
    }

    This doesn’t push items off the screen but it does essentially hide them. This won’t work for everyone’s needs (such as drop downs, although possible with this code would take some work). Just curious about the impact. It seems to be one of the better ways I have found.

  10. Please don’t read any sarcasm or condescension into my title — I mean it sincerely.

    If I have deliberately hidden content from my sighted readers using _display: none;_
    why would I need it to be accessible to screen readers?

    My normal solution for graceful degradation (particularly for non-javascript-enabled browsers) is to code the content as visible by default, then execute Javascript on page load to hide it. Under what circumstances would this leave a screen reader unable to read the content just as well as a standard browser would?

    That is: if the screen reader browser is Javascript-enabled, the content will become visible under the right conditions (e.g. a button is clicked). If it is not Javascript-enabled, the browser will default to displaying all content in full. If there is another option that I’m missing, I need to know about it so I can account for it in my future development.

  11. bq. Wouldn’t top: 100% (or left: 100%) work better than left with an arbitrary, obsolete-able static value, especially with overflow: hidden set on a parent element?

    Shifting content off the top of the screen is certainly valid as well (though without testing I’m not sure the mileage you’d get from 100%), but it does introduce some weirdness when you intentionally or accidentally bring focus to an item off-screen: the page will jump back to the top. Moving it off the left (or right in RTL languages) does not cause that issue.

    bq. Just wondering about the “newest” thinking on this topic. Here is what I am referring to: .accessibility { border: 0 none !important; clip: rect(0.1em, 0.1em, 0.1em, 0.1em); height: 0.1em !important; overflow: hidden; padding: 0 !important; position: absolute !important; width: 0.1em !important; }

    Good call, I forgot about that one. It doesn’t need to be that convoluted: position:absolute; clip:rect(1px 1px 1px 1px); should work just fine and would be accessible to assistive technology. The beauty of using a @class@ to manage this is that you can easily upgrade your accessibly hidden content strategy as better practices come up.

    bq. My normal solution for graceful degradation (particularly for non-javascript-enabled browsers) is to code the content as visible by default, then execute Javascript on page load to hide it. Under what circumstances would this leave a screen reader unable to read the content just as well as a standard browser would?

    It’s a relatively good strategy, but not all screen reader users surf the web with JavaScript turned off (nor should they have to).

    I’ll give you an example: in an accordion interface, screen reader user will not have access to content that is tucked away in unfocused sections unless they somehow figure out content is hidden in some way and then figure out how to unhide it. Browsing the web should not be that challenging.

    ARIA gets us partway there (allowing for you to define an interface and then control what’s showing an what isn’t), but not all assistive technologies support ARIA yet (and I’d wager even fewer widgets implement it).

  12. If we want to talk about all of the ways to hide content from a screen reader, we need to expand to use aria. aria is relatively new and not fully supported, but hopefully, in the future it will allow for better control. According to the WAI-ARIA specs, the aria-hidden attribute (aria-hidden=”true”) can be added to an object to tell the screen reader that the object should be hidden from the user. Using the css selectors, it is possible to use the aria-hidden attribute to style elements to be hidden, ex.

    [aria-hidden=”true”] { visibility: hidden; }

    It is possible that some day this attribute could be used to tell the screen reader that although it is not visible to the normal user, it should be visible to the user of a screen reader. (i.e. even though the style says, visibility: hidden; if the aria-hidden=”false” the object would be read by the screen reader.)

    But, I suppose until aria is fully supported by all of the browsers in use, we will continue to rely on other methods such as positioning content off screen to make hide content from the visual user while making it accessible to the users of a screen reader.

  13. I am fairly new to web design, and still learning the use of different functions, so it is interesting to see all these options. I am definitely a very big fan of overflow:hidden, I haven’t been web building for that long, but when I discovered overflow:hidden, it made things much easier.
    Another one I tend to use is display:none, and I am going to try out some of the other things you mentioned, to get a better perspective on what works best.

  14. nice tip Aaron, if you’re using this technique a lot the JS could be put into a function to make this easier to call.

    As wonkeythemonkey notes, we also often leave content visible and then hide with JS but I can see this causes an issue with screen readers with JS enabled since it just hides content for those users. If the control to show/hide is not accessible to that user then they will never see that content. Which is an accessibility problem if that content is essential or very useful to the page.

    We have a slide up/down contact form on a recent site we built (http://www.cambridgebs.co.uk/). It does have a normal link to a contact page but I wonder how that would fare to screen reader users if they have JS enabled?

    I am sure I read somewhere that a very high percentage of screen readers browse the web with JavaScript enabled (something like 85-90%) so this is definitely an issue worth raising. It’s also one that rarely gets talked about, so thanks for posting an interesting article on the subject.

  15. I know that I must be missing something.
    Why would I want for a screen reader to have access to something that I wouldn’t want a visual user to see?

    If I have chosen to hide something, why would I want that content available to a user of a screen reader?

    Thanks in advance!

  16. “MikeB”:http://www.alistapart.com/comments/now-you-see-me/P10/#15 is 100% correct, ARIA offers mechanisms for hiding content from assistive technologies (which is the next section in the book, coincidentally) and, as long as you’ve defined methods to unhide that content in a manner that ARIA-enabled assistive tech can make sense of, you should be fine. As he says, though, ARIA is not fully supported. Which leaves us in the pickle “Derek described a few months back in this very magazine”:http://www.alistapart.com/articles/aria-and-progressive-enhancement/. Detlev Fischer also offered “some great insight into ARIA”:http://www.alistapart.com/articles/the-accessibility-of-wai-aria/ in “that issue”:http://www.alistapart.com/issues/319.

    bq. I know that I must be missing something. Why would I want for a screen reader to have access to something that I wouldn’t want a visual user to see? If I have chosen to hide something, why would I want that content available to a user of a screen reader?

    As I’ve mentioned in other comments, it’s not so much the hiding that’s really the problem, but rather the ability to unhide the content in a reasonable and easily understandable way. The beauty of hiding content and still allowing it to be read by screen readers is that you don’t have to force a blind person (for instance) to figure out that you’ve got an accordion widget or tabbed interface and then force them to interact with it in order to access the content of your page.

    You work hard on your content and, unless you’re doing something nefarious, you probably have the content hidden because you want to streamline the interface, but you want it read _eventually_. By accessibly hiding content, you don’t put any additional barrier between people who require assistive technology and your content and you can keep your streamlined interface for everyone else.

  17. I had thought that positioning off page was the best way to go for cases where we wanted to hide & show certain pieces of content & coded accordingly.

    Then my organization hired an accessibility consultant, who was blind. The consultant’s feedback was that he didn’t prefer this approach. He wanted to hear the same content as a sighted user. He also valued having less content on the page to have to listen to – similar to why we’d use a widget for sighted users, so they can just skim & only view the content they really want to see.

    We also worked out adding some hidden content (via positionig off page) that would help orient a non sighted user to the state change – for example, something like “click to expand”. I’m hopeful that Aria will eventually help out a lot with these types of scenarios.

  18. …in the literal sense of the word. Your article provoked some useful discussion of the accessibility thing wrt hide/show, which I for one hadn’t thought about. The current situation is clearly not ideal for blind users, but comment #20 shows how one’s best attempts may backfire. This Aria thing (which I’d never heard of) sounds as if it might be the way to go in future).

    PS What’s the rest of the book about?

  19. In the old days we used LAYER tags and Z-INDEX. Is this not a viable option for hiding text? Just create one div that is 100% high and wide and not transparent and then send your hidden objects behind it?

  20. For nav menus that use images as links I have been using the following method to hide the link text…but hopefully keep it readable by screen readers…

    a {
    background-image: **path to image**
    width: **bg-image width**
    height: **bg-image height**
    text-indent: -9999px;
    overflow: hidden
    }

    Acording to this article it would seem that the text would still be readable by screen readers…

    http://www.abilitynet.org.uk/webarticle67

    Any responses are greatly appreciated…

  21. Hey Aaron,

    Great article. I decided to take a stab at changing the jQuery hide() function to use this technique to hide elements as apposed to display:none.

    I got it working it seems 😉 Have a look over here: http://goo.gl/2nIHQ

    Thoughts?

  22. It could be that I totally missed the point of this article but when you hide stuff visually it should be hidden from screen readers too. The “Idea” presented here is to keep hidden stuff available to screen readers. THAT is ridiculous. Every modal window would always be in view for screen reader users. There would be no expand/collapse for accordion controls … That is just plain wrong.

    The only use for positioning off-screen – is not to hide, but to place a message on the page that is intended for blind visitors and specifically not for visual users. For example there might be a section of the page that is visually obviously a log in section, but no heading text is available. You might position a heading “Log-in form” off screen so a blind user would find that section using headings navigation (the H key). Another nice example of using this technique is a skip link, positioned off screen for blind visitors, but which becomes visible when focused and basically hidden for mouse users. That is the case for the skip links on my site.

  23. This is also incorrect: “height: 0; width: 0; overflow: hidden; Element is collapsed and contents are hidden Content is ignored by screen readers”

    I just double checked and it is read everywhere I tried: JAWS 11 with IE and FireFox, WindowEyes 7.5 with IE and FireFox and NVDA 2010.2 with IE and FireFox.

  24. The main point that I take away from the article is that just because I cannot see something on the screen, it does not mean that a screen reader will also not see and thus read the content. When using a JavaScript library such as jQuery, you don’t always know what the animation is doing and it is possible that it will change in future releases. I was working on a page and animating the opacity of an object and later realized that the screen reader still had access to that content. I changed my code to use a callback function to apply a class that set the visibility to hidden after the animation was complete. This is the opposite of his example, but the principle is the same.

  25. About MikeB’s commment. If the principle being advocated is the use of callback functions, then you have used that principle in a way that is effective for everybody. The author here suggests the use of that principle to explose for screen readers all hidden content – which, as I suggested above, is a disaster!

  26. Excellent stuff! Thank you for sharing. I’m also seeing more and more mobile websites on smart phones (iphone and android) using these techniques which is important because of the small screen real-estate. Worth sharing is mobileInDesign, http://www.mobileInDesign.com which shows mobile website trends.

  27. None of the projects I’ve ever worked on had enough budget and resources for working on accessibility. I don’t know if there is a better way to do this, or a kind of international force for implementing it. But whatever it is, I know that it’s budget which directs products, not us directing it. A good example is my own website, http://www.thoughtresults.com which can not be updated on a daily basis, just because I don’t make money enough to recruit for it. So, I suggest that we take accessibility as a lower priority concern.

  28. Thank you for give me the chance to learn more about Hollaback scripts, but I have question:
    ‘(function(){
    var $button = $(‘#myButton’),
    $text = $(‘#myText’),
    visible = true;
    $button.click(function(){
    if ( visible ) {
    $text.slideUp(‘fast’);
    } else {
    $text.slideDown(‘fast’);
    }
    visible = ! visible;
    });
    })();’
    how to change the size of the button?

  29. Nice article.

    The absolute positioning method is something I’ve never really thought of using before (to to hide content anyhow). In terms of accessibility I guess it is the best way of going about hiding things. However as some have already mentioned, I can’t help but feel it’s a little… hacky.

    I’m quite surprised W3C haven’t considered adding a new display decoration to CSS3, that does what we all require – hides content, leaves no space, but is readable by screen readers.

  30. Thanks for the article and the interesting discussion! Since the discussion somehow broke off after the strong statement by Jim Thatcher (“This is the wrong advice”) I have tried to revise and order the arguments in favour of both approaches (hiding or not hiding content for screen reader users) in a short article “Dealing with hidden content: what is best for screen reader users?”:http://www.bitvtest.eu/articles/article/lesen/hidden-content.html
    I’d be glad to hear views especially of screen reader users (expert and not expert).

  31. bq. The author here suggests the use of that principle to explose for screen readers all hidden content — which, as I suggested above, is a disaster!

    I’m sorry, but I disagree with you (at least partially) Jim. While it is true that you may want to hide some content from both sighted and non-sighted users, in most cases content that is hidden by default and meant to be exposed via JavaScript (as in a tabbed interface or accordion) is never exposed to screen readers because the default styles turn it off and (in some cases) those users are surfing with JavaScript turned off (because of its traditional accessibility issues).

    There’s also the issue of alerting users to changes/updates in the content. ARIA provides mechanisms for this, but support is currently uneven at best.

    All of that said, I _do_ think it makes sense to hide *unnecessary* content with display:none in order to speed document traversal for keyboard users and screen readers as well as to limit potential confusion. I would group lightboxes, modal dialogs, tooltips, etc. in this category. This assumes, of course, their function is not required in order to actually use the page/site. If you are using a modal login box, I’d recommend a link to a login page somewhere prominent.

    bq. If jQuery has non-accessible code, why not fix jQuery so that it produces accessible content by default? After all, it’s open source.

    It’s a noble idea, for sure, but one fix may not be best for everyone. Also, techniques change. I think it’s fine to have a certain default in jQuery and then to override it with a @class@-based hiding mechanism that you control and can update as you deem necessary.

    bq. Thank you for give me the chance to learn more about Hollaback scripts, but I have question: how to change the size of the button?

    CSS.

    bq. Thanks for the article and the interesting discussion! Since the discussion somehow broke off after the strong statement by Jim Thatcher (“This is the wrong advice”) I have tried to revise and order the arguments in favour of both approaches (hiding or not hiding content for screen reader users) in a short article Dealing with hidden content: what is best for screen reader users?
    I’d be glad to hear views especially of screen reader users (expert and not expert).

    Reading it now.

  32. First off Rovo makes a good point, I think the truth is that placing things off screen versus a proper solution is a shortcoming of the readers themselves, this needs to be improved all around, if screen readers want to avoid elements styled with “display: none;” I think this is the perfect scenario for them to avoid the content. However, “visibility: hidden;” seems like the perfect method for us, and it should be the way the screen readers work, this is by far the cleanest most meaningful, logical implementation for hidden text thats screen readable.

    To recap: no, neither of the methods mentioned above work, but “in a perfect world” screen readers would support them.

    Beyond screen readers, I wonder about search engines as well, can they crawl via “display: none” or “visiblity: hidden”? Becomes a much more usable scenario.

    But I digress, before my long post my original point was to post updated code for a method to do this that removes the inline style created by a framework like jQuery (in my example jQuery was used.)

    here is my solution:

    $navMenu = $(‘#mastHead .menu’);
    $navButton = $navMenu.find(‘dt’);
    $navDropDown = $navMenu.find(‘dd’);

    $navMenu.click(function () {
    $(this).toggleClass(‘active’);

    // cannot be toggle, too complex of an ordering is required
    if ($navMenu.hasClass(‘active’)) {
    $navMenu.addClass(‘down’);
    $navDropDown.fadeIn(200, function() {
    $navDropDown
    .addClass(‘show’)
    .attr(“style”, “”);
    });
    } else {
    $navDropDown.fadeOut(200, function() {
    $navDropDown
    .removeClass(‘show’)
    .attr(“style”, “”);
    $navMenu.removeClass(‘down’);
    });
    }
    });

  33. ok, here is more or less the meat of the post:

    .attr(“style”, “”);

    thats needed to remove the inline style, but be careful where you do it, if you’re animating anything this will need to be done in a certain order to avoid glitches

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA