Hiding content untangled: Hiding vs. moving out of the visible viewport

This blog post is once again prompted by something I encountered in the wild. The other day, I was testing browserid.org‘s account manager for accessibility and encountered some inconsistencies in keyboard navigation and screen reader usage. For one, there are “edit” buttons next to the “Your E-Mail addresses” and “Password” headings whose usability wasn’t obvious to me. To my screen reader, the “remove” buttons next to the e-mail addresses linked to my account, as well as the two password entry fields, were visible without me having to actually press these “edit” buttons at all. I could perform all actions without a hitch, so these buttons seemed superfluous and just adding noise. Secondly, even when just navigating through the page via the tab key, I couldn’t find anything that these “edit” buttons could be used for.

The solution came to me when I asked my significant other, who is sighted, to look at the page with me. For her, the “remove” buttons and password entry fields were not visible on initial page load. When I started navigating the page with NVDA’s virtual cursor, the buttons magically appeared. When I moved in the opposite direction, they disappeared again. When I navigated via tab, they appeared and remained visible from then on.

The problem here was that the content “hiding” was done in a way that visually hides the content from the naked eye, but not from my screen reader. Furthermore, the fact that this page has different interaction models for keyboard and mouse users was not taken into account. In short: a wrong technique was used to hide the content.

This blog post is an attempt at explaining the different “hiding” models as well as trying to get rid of some of the misunderstandings and misconceptions I’ve encountered over and over over the past ~10 years.

Some basics

To understand what’s happening, you need to know (or remember) this: Screen readers as well as other assistive technologies for people with disabilities use a collection of objects to convey information about the web page to the user. These objects are structured in a tree-like structure, with the document being the root, the navigation area, headings, sections etc. being this root’s children and so forth. Accessibility techies call this the “accessible tree”. It is a sub set of the tree built from the HTML source code in the browser’s document object model (DOM). Not all elements need a representation in the accessibility tree, so the mapping isn’t always 1:1.

The rendering engine, in Firefox’s case Gecko, applies several attributes to these accessible objects that relay important information to the user with disability. For this information, the engine does not only use attributes supplied by the individual HTML tags, but also some styling information from the CSS. An example of this CSS-based information is that about text styling and attributes, colors etc.

Some information, however, is not used, like the final position of a container via CSS. A div container may, for example, be shown in the upper right-hand corner of the site, right next to the navigation bar, but its code may be somewhere at the end of the source file. The screen reader will find the text in that container near the end of the accessible tree, not right next to the navigation, because the styling information for this position is not used. If you’d like to know more about this, read this article of mine.

Hiding is not equal to hiding

Some CSS statements, however, are being followed to the letter. In IE, the screen reader does it, in Firefox, the Gecko engine does it for the screen reader, and has being doing so for over ten years now. Elements styled with “display: none;” or “visibility: hidden;” are not included in the accessibility tree! Only if that element’s styling is changed via JavaScript or similar to make it visible, it is being inserted into the accessible tree, and an event is being emitted to let the screen reader know that this insertion just occurred.

Other statements for “hiding” like “left: -9999px; top: -9999px;” are not being used. These elements appear to the screen reader just as any other currently visually visible element on the screen is.

Once again so this sinks in: Elements styled with “display: none;” or “visibility: hidden;” are always hidden from screen readers as well. This is true for screen readers on Windows like NVDA or JAWS, and has been so for at least the last ~7 years. Orca on Linux, VoiceOver on OS X and iOS also adhere to this rule. JAWS has consistently supported this since version 7, which was released in 2005. All other screen readers I know do this right, too, and have been for ages. Why this rumor that one can provide extra content to screen readers via elements styled with “display: none;” keeps sticking around, I have no clue. It is definitely wrong! Screen readers completely ignore elements styled with “display: none;” or “visibility: hidden;”.

So when do I use what?

If an element or group of elements should only become visible after the user performed a conscious action, use “display: none;” or “visibility: hidden;”, depending on your requirements. A good example of this can be seen by many bloggers each time they’re in their WordPress 3.3 backend. The main menu items like “Dashboard”, “Article”, etc., have menu items hidden that only become visible if a) one hovers the mouse over them or b) one navigates there via tab and presses enter. Some magic is performed, and the “display: none;” styling is removed, and the elements become visible. In addition, WordPress correctly uses the WAI-ARIA attribute aria-haspopup=”true” on these menu items to indicate that there are items that become visible once a particular action is performed.

Had the WordPress folks used a technique to merely remove the elements from the visible view port, my screen reader would see all sub menu elements of all categories. My user interface would be much more cluttered than that of sighted people. All advantages of a lean and mean interface would be gone. And yes, I, too, enjoy the niceties of a clean interface where I can show and hide the stuff I need to work with or not. If, like in the WordPress case, the correct markup is being used, I do not need to see all content immediately to know that it may be there if I need it. On the contrary, if it were all shown, my interface would be cluttered and difficult to navigate, too!

The wrong method to use is the one I explained at the beginning of this article. The “remove” buttons and password entry fields of the BrowserID account manager were merely moved out of the visible view port rather than completely hidden.

Another useful application of content moved out of the view port are “skip” links. WebAIM have an article on these if you want to dive into this matter further.

In conclusion

It is my sincere hope that this blog post helps to clear up some confusion about the types of “hidden” content, the effects “display: none;” vs. negative positioning has, and when to use what properly. A good rule of thumb might be: If something should remain hidden until the user performs a conscious action, use “display: none;”. Should something, on the other hand, become visible when navigated to via the keyboard, or be discoverable by screen reader users right away, use negative positioning.

Questions? I’m sure there are! So feel free to post them here! And don’t be shy. Only who asks no questions will remain in the dark. 🙂


15 thoughts on “Hiding content untangled: Hiding vs. moving out of the visible viewport

  1. Hi Marco,

    I have a question: most Javascript libraries, such as jQuery, implement show/hide behaviours using display:none. This is used for modal dialogs (usually located at the end of the DOM tree) as well as tabbed content, popovers and accordion-style expanding elements (usually adjacent to the trigger in the DOM). Is this bad for accessibility, given the popularity of these Javascript libraries?

    I used to believe that it would be better for these elements to be hidden using off-screen techniques, so that screen readers could access their contents without requiring Javascript. I think your article proves me wrong, though, and you are happy with Javascript toggling the display property of elements, and would prefer not to encounter content that is visually hidden. Is that right?

    Either way, I assume it remains the responsibility of the developer to properly alert screen readers to the dynamic appearance of an element, and make its contents accessible. And currently, it would seem, that’s the exception rather than the rule, especially when dynamic elements are put at the end of the DOM. I blogged about it here: https://blog.isotoma.com/2011/10/two-accessibility-gotchas/

  2. Hi Francois,

    yes, I would prefer it the way JS libraries do it now already, so their way by using display: none; is the correct way.

    The important thing, when making contents like a dialog visible, is to also set keyboard focus there if possible. You want the user to interact with the dialog anyway, so it makes sense to put keyboard focus there already, and providing the context for the dialog via aria-describedby and such techniques. That way, the user does not need to search for the new content, but is put there straight away. In other cases, such as my WordPress example, the new content appears straight below the menu item whose sub menu is to be activated, so it is easy to find. Yet other cases might benefit from the clever use of a live region. It really depends on the use case. And yes, the one thing I really do not want to see as a user is all content visible to me but visually hidden by moving it out of the view port. Esp when it is likely that I don’t want to interact with 3/4 of the dynamically available stuff at the moment.

    I blogged in early 2008 that JavaScript is not bad for accessibility at all.

  3. I have a vague memory of reading more than one article for developers recommending the technique of moving things outside of the “visible” area. Do you know why that is? Other than the mistaken belief that screen readers ignore “display:none”, I mean. Is it faster to reveal things by moving them rather than toggling their visibility? Or maybe it’s for measuring rendered sizes? Just curious.

    Side note: I’ve actually stumbled across a couple of web sites that clearly were trying to move something far enough away to not be seen, but apparently ONE THOUSAND PIXELS doesn’t mean as much as it used to, and it was clearly visible. 🙂

  4. This is very valuable, thank you Marco. A11y is an important consideration when we interview webdev candidates, and blog posts like these help teach the world how to make websites with accessibility in mind.

  5. Thanks, that’s good to know.

    From memory, `display: none` messes up iframe loading in some browsers, so the `visibility: hidden` tip provides a potential work-around for that.

    I have a question about the opposite scenario – leaving content visible to screen readers but hiding it from the visible page. Of course you can use `top: -9999px; left: -9999px`, but how about `height: 0; overflow: hidden`?

  6. Good post Marco! It’s interesting to get the perspective of a blind user (and your technical knowledge and experience) coming across these techniques. Will re-tweet.



  7. That is (at least) the third time in the last month or two that I have seen a comment that appears, at least, to confuse the issue of off-screen absolute positioning for aural ATs with the barely related issue of image replacement, along with a link to an article by Jeffrey Zeldman. In all occasions, it appears that Zeldman’s comment about a large box may have been misunderstood: thus, it is somewhat taken out of context and misapplied in reference to a different method that does a different task and does not create any such box. Moving text outside of its element will necessitate and invisible box, but absolute positioning does not. Different situations and intentions; different solutions and results.

    To Sean, who asked about setting an element’s height to 0: it is highly inadvisable and we never do that to accessible content, because VoiceOver insists that elements have dimensions (specified or otherwise) if they are to be announced. As far as I am aware, this is still extant in VO. It is not really correct, in my opinion, but it is another quirk with which we have to work.

  8. One concern I have with using display: none is that this also hides content from the browser’s search functionality. Isn’t this a backwards step? By trying to simplify the appearance of our pages are we possibly removing useful functionality? I guess the counter-argument is that, for example, well organised content and well named tab headings will make it obvious to all users what content they can find within hidden tabs and which tab to open, and perhaps search, to find the content they’re after. Even so, I do often use the browser search to find content on a page and this won’t return content hidden using display: none.

    I came across your very useful blog post whilst searching for opinions on this; but haven’t found much discussion on the subject thus far; and this seems as good a place to ask the question: Are we limiting useful functionality if we use display: none?

  9. Excellent stuff going on here, Marco! Just stumbled onto your pages while looking into the recent accessibility goings-on in the HTML5 world. I have found the following to be quite interesting from the folks over at Paciello: http://www.paciellogroup.com/blog/2012/05/html5-accessibility-chops-hidden-and-aria-hidden/ as well as something in the wayh of a corner case in which JAWS does indeed announce display: none. It may be the reason why the confusion around JAWS announcing display: none persists. “As stated earlier, JAWS announces content in a span element hidden with display: none if it is in an anchor element. This only works with a span element; other inline elements used in an anchor element, such as em, strong, abbr, code, and so on, are not announced in JAWS.” Please see http://juicystudio.com/article/screen-readers-display-none.php#jawsdisplaynone for the details. Please note that I did not attempt to replicate this behavior in JAWS in the version 12.x I am running, so it may have been corrected by now. However, it may suggest why the confusion around the display: none in JAWS (and perhaps screen readers generally) persists. Thanks for sharing the info you have thus far, and keep up the fantastic work!

  10. Hi. I would like to ask a question. I have a help link which, when clicked, toggles a hidden div which contains a paragraph with the help info on it. Between these elements there is another one. The help button is used with background image.


    This is the help info

    $(‘.help’).on(‘click’, function(){

    Now, when the user pushes Enter key, even though the info is displayed on the screen, it does not get avaliable for the screen reader. I am using aria-describedby pointing to the paragraph id, and the paragraph has role = tooltip.
    Do you think you could help me with this one, please?
    Thanks a lot.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.