Summary

Jim Thatcher noticed some interesting behaviour whereby screen readers announced content in an anchor element that is hidden with display: none. Content hidden with display: none is not usually announced by screen readers, apart from labels for form controls, regardless of the verbosity settings.

Looking into it further, there are certain circumstances where content hidden with display: none is announced by JAWS and Window-Eyes. The circumstances are explained in this article, but it is always better to position content aimed at providing context for screen reader users off-screen, as content hidden with display: none should remain hidden.

Author: Gez Lemon

Contents

Hiding Content with display: none

When an element is hidden with display: none, the browser doesn't generate a box for the element; the element is not visible on the screen, and the layout of the page isn't effected by the element. As screen readers are supposed to read the screen, it makes sense that they do not announce content that is hidden with display: none.

Becky Gibson noted a few years back that labels for form controls hidden with display: none were announced by JAWS and Window-Eyes. I had noticed recently that JAWS announces span elements hidden with display: none in anchor elements, but that the span was not announced by Window-Eyes. When I mentioned this to Jim, he sent me files that he was using; sure enough, the content was being announced in Window-Eyes, which was a mystery to both of us.

Hiding Content that Provides Context

There are situations where developers might want content to be hidden visually, but revealed to screen reader users. For example, a design might call for ambiguous link phrases, such as "More", where the context is visually evident, but might be lost to screen reader users. To get around this, a developer might do the following:

CSS

.context
{
    display: none;
}

Markup

<a href="...">More<span class="context"> about XYZ</span></a>

The problem is that hiding the content with display: none also hides the content from screen readers (more about this later). To get around this, developers position the content off the screen, such as using the following technique:

CSS

.context
{
    position: absolute;
    left: -999em;
    width: 1em;
    overflow: hidden;
}

Using the same markup as above, the contextual information isn't displayed on the screen, but is announced to screen reader users.

JAWS and display: none

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.

Steve Faulkner ran some tests, and determined that this behaviour was introduced in JAWS version 7.1 and only for Internet Explorer.

Window-Eyes and display: none

The content of the span in the markup snippet below is announced in JAWS 7.1 and later with Internet Explorer, but it is not announced in Window-Eyes.

CSS

.context
{
    display: none;
}

Markup

<a href="...">More<span class="context"> about XYZ</span></a>

Jim Thatcher had come across a couple of websites where content was hidden with display: none, but was being announced by Window-Eyes 5.5. Playing around with the CSS in Jim's examples, it turned out that the reason why content hidden with display: none was being announced in Window-Eyes was because an ancestor element had a URL set for the background-image CSS property. So if the CSS for the above example included the following rule-sets, the content hidden with display: none would also be announced in Window-Eyes.

a
{
    background: url(hidden.gif);
}

.context
{
    display: none;
}

I suspect that the reason why this works when the CSS background-image property has a value on an ancestor is to cater for inaccessible image replacement techniques, such as the Fahrner Image Replacement technique explained by Doug Bowman (but not recommended by Doug).

There are a couple of extra interesting points.

  1. It doesn't matter whether the ancestor is the immediate parent, or whether the ancestor is much higher in the hierarchy — if a container has a value specified for the background-image property, content hidden with display: none will be announced in Window-Eyes.
  2. If a value is specified for the background-image property on the body element, content hidden with display: none is not announced, unless there is another ancestor after the body element with the background-image property set.
  3. Unlike JAWS, the element hidden with display: none does not have to be a span within an anchor element; it doesn't even have to be contained within an anchor element. Complete div elements or anything else will be announced in Window-Eyes if they're hidden with display: none, but have an ancestor that has a value specified for the background-image property.
  4. If an anchor element itself is hidden with display: none, and has an ancestor with a value specified for the background-image property, it is visible to Window-Eyes, even though it isn't in the browser's natural tab order.

This is very strange behaviour, where points 3 and 4 can cause serious problems for Window-Eyes users. If content has been deliberately hidden from everyone, including screen reader users, Window-Eyes users will be exposed to that content if the background-image property has been set on an ancestor. I can understand JAWS' behaviour of announcing content that really shouldn't be announced when a span element is used within a link phrase, as they're just using heuristics to help their users. The Window-Eyes approach seems a little more reckless, although probably just as well-intentioned. The background-image property is used extensively, and far more popular than inaccessible image replacement techniques. Pages that deliberately hide content from everyone with display: none are broken in Window-Eyes if a value is provided for the background-image property.

Update - towards a solution

Jared Smith asked in the comments whether the results are any different if both display: none and visibility: hidden are used.

JAWS behaves exactly the same when a span element is hidden with visibility: hidden in an anchor element as it does with a span element hidden with display: none.

Window-Eyes doesn't do the same thing if visibility: hidden is used. Content hidden with visibility: hidden is not announced in Window-Eyes, even when an ancestor has a value specified for the background-image property. On its own, visibility: hidden might not be desirable, as it generates a box that effects the layout. Fortunately, using visibility: hidden also works with display: none, which doesn't generate a box, and therefore has no effect on the layout. So issues introduced by Window-Eyes' strange behaviour can be avoided using the two properties together:

.hide
{
    display: none;
    visibility: hidden;
}

Thanks to Jared for coming up with a solution to the problem.

Translations

Category: Accessibility.

Comments

  1. [screen-readers-display-none.php#comment1]

    This is quite interesting Gez, and I can see why its been made to work that way too because it could definately enhance some user's experience on JAWS for example.

    I'm not sure of my opinion about whether its a good thing or a bad thing yet though, as I'm still absorbing the idea. I can see it might be an issue on 3 and 4 for Window-Eyes users as you say so it needs to be approached with caution.

    But its damn interesting behaviour for sure. This might be an interesting one to throw at my students...

    Posted by Steven Clark on

  2. [screen-readers-display-none.php#comment2]

    Excellent writeup! I've experienced this in the past, but have never been able to determine why hidden elements are sometimes read. Thank you for your investigative reporting.

    Now, what are we to do? This will become increasingly more problematic as sites use DOM scripting and AJAX more. I have an entire application that is rendered inaccessible because of this. Developers need some mechanism for ensuring that content that is hidden is truly hidden to everyone. Hopefully you'll pass this onto the screen reader folks (though they rarely listen to us mere web developers).

    Posted by Jared Smith on

  3. [screen-readers-display-none.php#comment4]

    Hi Jared,

    Does this same thing impact visibility: hidden? In other words, are the results any different if both display: none and visibility: hidden are used?

    That's a great question, which fixes the problem — thank you.

    JAWS behaves exactly the same — if the span is hidden with visibility: hidden in an anchor element, it's announced; for any other element, it is not announced.

    Window-Eyes doesn't do the same thing if visibility: hidden is used. For the issue you raised about sites that use DOM scripting to hide/reveal content in web applications that breaks in Window-eyes, visibility: hidden can't be used on its own, as it generates a box that effects the layout. However, if visibility: hidden is used in conjunction with display: none, it doesn't effect the layout, and the content isn't announced to Window-Eyes, even when an ancestor has a value specified for the background-image property. So the following completely fixes the issue:

    .hide
    {
        display: none;
        visibility: hidden;
    }

    Thanks again for a great suggestion.

    Posted by Gez on

  4. [screen-readers-display-none.php#comment5]

    Thanks for this interesting post.

    Just wanted to add a note about the "off-left" technique you mentioned. A few years back, WebAim had a good article on that which suggested it was better to use "off top" instead, because "Placing the content above the viewport is preferable to placing it to the left or right of the viewport because both of these other directions cause display irregularities in some browsers."

    http://www.webaim.org/techniques/css/invisiblecontent/

    The article didn't unfortunately say which browsers, and it is likely that as this was a few years ago, the issues may not be the same anymore.

    I have tended to stick with the "off-top" approach, without any issues.

    Do you know anything further about that difference?

    Posted by Anup on

  5. [screen-readers-display-none.php#comment6]

    Hi Anup,

    I have tended to stick with the "off-top" approach, without any issues.

    Do you know anything further about that difference?

    I have heard that positioning content to the left of the viewport can cause horizontal scrollbars to appear in older versions of Opera and Safari, but I don't know what versions and under what conditions. I always test with both browsers, and I've never encountered the problem, but would be interested to learn more if anyone else has encountered issues using this technique.

    Posted by Gez on

  6. [screen-readers-display-none.php#comment7]

    This is quite interesting Gez, and I can see why its been made to work that way too because it could definately enhance some user's experience on JAWS for example.

    Steven I agree this is interesting, I read somewhere on one of the SEO blogs that using display: none; (when we use it to hide links and content) can damage our domain on search engines like Google. I don't know is it true as I haven't tested it on my domains. Regards

    Posted by Tomasz Gorski on

  7. [screen-readers-display-none.php#comment8]

    Unless I've missed a trick, your last example has the properties the wrong way around (display: hidden should be display: none).

    Also, I think the end of "This means that the first version" has gone missing.

    Good info tho!

    Cheers,
    Jake.

    Posted by Jake Archibald on

  8. [screen-readers-display-none.php#comment9]

    Hi Jake,

    Unless I've missed a trick, your last example has the properties the wrong way around (display: hidden should be display: none).

    Good catch - thank you. They were the right way round in the description, but wrong in the code.

    Also, I think the end of "This means that the first version" has gone missing.

    Another good catch - thank you.

    Posted by Gez on

  9. [screen-readers-display-none.php#comment10]

    Thanks for this.

    We were looking at the same issue (in context of an expanding/collapsing menu) and are in correspondence with GWMicro about it.

    Your solution is much appreciated (though we still think we shouln't be forced to write a hack and GWMicro should fix it).

    Posted by Grant Focas and Andrew Downie on

  10. [screen-readers-display-none.php#comment11]

    I wonder how to interpret these findings.

    I was initially thinking about it having an effect on image replacement techniques, and it would help in situations where hiding text by text-indent or absolute positioning is somehow not possible; but, at the same time, there's more screen readers than Jaws and Window-Eyes. If I started using this, I'd be potentially locking out visitors with other screen readers, right?

    Posted by Matthias Willerich on

  11. [screen-readers-display-none.php#comment12]

    Hi Matthias,

    I was initially thinking about it having an effect on image replacement techniques, and it would help in situations where hiding text by text-indent or absolute positioning is somehow not possible; but, at the same time, there's more screen readers than JAWS and Window-Eyes. If I started using this, I'd be potentially locking out visitors with other screen readers, right?

    Yes, you're right - and you would also be locking out users of JAWS prior to version 7.1. The behaviour is obviously just an attempt by JAWS and Window-Eyes to help their users, although the Window-Eyes repair technique causes more accessibility problems than it fixes. I definitely wouldn't recommend that developers include display: none in their image replacement techniques.

    Posted by Gez on

  12. [screen-readers-display-none.php#comment13]

    if have used display:none often. on a webpage i realized some "tooltips" with further informations, it works really nice, but now i'm not sure if the searchengines rate the invisible content as "keyword-stuffing, cloaking" or something like that. any mentioned about that?

    Posted by Schreibtisch on

  13. [screen-readers-display-none.php#comment14]

    Anup above asks about what difference it makes where you position content off-screen. I tend to use off-left because I was finding that if you position extra context for an anchor off-top, Window-Eyes puts that context into the its link list as a separate link to the text it clarifies. Has anyone else noticed that?

    Posted by Benjamin Hawkes-Lewis on

  14. [screen-readers-display-none.php#comment16]

    Well, this certainly throws a wrinkle in my testing plans. I often use display:none to do A/B split tests on various headlines, images or other elements. It's just much easier to hide that content in a DIV then it is to use AJAX or some other replacement technology.

    With regards to SE's i have never had an issue with keyword stuffing... I even have entire paragraphs hidden as I test one copy vs another...

    -D

    Posted by Dog on

  15. [screen-readers-display-none.php#comment17]

    Well, this certainly throws a wrinkle in my testing plans. I often use display:none to do A/B split tests on various headlines, images or other elements.

    You can continue to do that - if you have the background-image property specified higher in the document tree, then adding visibility: hidden to your class/id that hides the selector will ensure it continues to work in Window-Eyes and JAWS. However, I do agree with Grant Focas and Andrew Downie that this should be fixed by GW Micro.

    Posted by Gary on

Comments are closed for this entry.