Hiding Content for Accessibility
For years now, we've used a number of techniques for hiding content offscreen for accessibility purposes. We do this because the content is still accessible to screenreaders while being removed from the interface for sighted users.
An article over at Adaptive Themes reviews a number of techniques for hiding content that were considered for inclusion on a Drupal 7 project (but certainly applicable to any project).
Here is a summary of those techniques and the pitfalls of each technique:
Text Indent
.element-invisible {
text-indent: -9999em;
outline: 0;
}
Unfortunately, this technique doesn't work with RTL (Right-to-Left) languages.
Position Absolute and Collapsed
.element-invisible {
height: 0;
overflow: hidden;
position: absolute;
}
In this case, Apple's Voice Over will not read content within an element that has zero height.
Position Absolute and Offscreen
.element-invisible {
position: absolute;
top: -999999em;
left: auto;
width: 1px;
height: 1px;
overflow:hidden;
}
In this case, if you have focusable content within the positioned element, the page will scroll to that element, thus creating an unsettling jump for sighted users.
Clip Method
.element-invisible {
position: absolute !important;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
}
The article ends with this final technique and is the solution they ended up using on their project.
With the work I've been doing at Yahoo!, we had been using the Position Absolute and Offscreen method. But sometimes we wanted to set focus to offscreen content. We had switched our technique to the Clip Method but uncovered differing behaviour between browsers.
Everything works great in Internet Explorer and Firefox. However, in Webkit (Chrome and Safari) and Opera, there's an interesting behavior when the element is at the edge of the screen. If the element, when unclipped, is large enough to force a horizontal scrollbar, will force a scrollbar even when clipped.
This seems to go against the CSS 2.1 guidelines that say:
Content that has been clipped does not cause overflow.
However, by forcing a scrollbar in Webkit and Opera, it does, in fact, seem to cause overflow. So how did we get around this?
Positioned, Clipped, and (almost) Collapsed
We combine a few techniques into one:
.element-invisible {
position: absolute !important;
height: 1px; width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
}
Using absolute positioning, we take the element out of flow so as not to affect the layout of anything around it. With a height of 1px, the element should still be visible for Voice Over to read the content. The clipping removes any visible trace of the element from the page.
Any focusable elements inside are still focusable, so depending on placement within the overall layout, some considered placement may still be of concern. Although, I might question why you are focusing on an element that was so far removed from the overall flow of the document.
We've only begun using and testing this technique, so even this may not be perfect. Any feedback and suggestions are quite welcome.
Conversation
Interesting approach(es) to hiding content. I had no idea that Apple's Voice Over wouldn't read 0 height content.
With all of these possabilities in mind, do we know how search engines react to hidden content? There's been a number of SEO discussions in the past on the topic of search engines not liking it when content is hidden.
If we use width/height/overflow, then why do we need clip?
Thanks for the heads up regarding the Webkit/Opera issue btw :-)
@Thierry: without the clipping, you have a 1px element that is still visible. Any background colours or anything else drawing in that 1px would be noticeable.
Hi Jonathan,
Good point about the possibility of having a colored dot on the page.
For the Webkit/Opera scrollbar bug, I believe we could fix it by using position:fixed rather than absolute, Using something like this may be:
That should kill the unwanted scrollbar, but unfortunately that would also bring back the tabbing navigation issue since any focusable element in there would make the page scroll.
As a side note, what do you think of dropping the "," notation, and go with:
The spec says: "User agents must support separation with commas, but may also support separation without commas".
Should we expect browsers to drop support for space separation any time soon?
I have always been told to set the element to
display: none;
.Does this not work?
This clip technique is also what's provided in the .visuallyhidden helper class in HTML5 Boilerplate.
@Thierry: Only IE recognizes the syntax without commas.
@Paul: It's nice to see implementations elsewhere. I hadn't seen documentation on this technique until it was shown to me by a co-worker.
Sorry for the spam, but your post got me thinking :)
If this variation is a patch for the "clip property" method, then why not dropping that technique altogether since it fails in some browsers?
Why not going with a rule in which each declaration is used for what it's supposed to do rather than used to "fix" another declaration within the same rule (does that make sense?).
It is this:
Versus this for example:
@Paul - I like the class name Boilerplate is using
@Jonathan: I believe it is the other way around. All browsers recognize the syntax without commas, but IE 6 and 7 that do not recognize the "comma" separated syntax.
Great article. I've been using the "Position Absolute and Offscreen", but this is far better. Thanks.
Add “text-align: left†to the Text Indent example, fixes the RTL pitfall.
I use a variety of methods - for skip navigation items, I style up the :focus and bring the content onto the screen (if you are physically impaired and use TAB to get around the screen - you still want to see these). In the non-focussed state I use:
Haven't had any issues with that.
I also use a similar technique for hiding additional text (for users with screen readers).
For example:
and then use the same CSS as in the non-focussed skip link, but change the class name to .hidden
I haven't had reports of any issues with this.
I have been using the text-indent method for quite some time now, and has no real issues with it - and I'm an RTL user.
The only thing I noticed is that for safari I also need to add 'overflow:hidden'.
Can you tell me what you mean when you say it doesn't work?
Been using the text-indent method for years now, and except for extreme cases with a mixture of relative and absolute positioning, it works great.
Would also like to know the issues you where talking about?
accept for the RTL issue you where referring to, isn't this the best and easiest way to use ?
Text Indent issues with RTL are easily solved with setting direction:ltr;text-align:left on the element you wish to hide.
btw - a thread exactly about this issue in html5boilerplate issues - https://github.com/paulirish/html5-boilerplate/issues/194
When using the Position Absolute and Offscreen method I have found it is better to move the element to the left rather than to the top -- in the interest of keyboard users. The reason is it lessens the occurrence of the user being/feeling bounced around (going to top, then back again). When the element is moved off screen to the left the user doesn't get bounced when tabbing and the whole use feels more natural.
Hi Jonathan,
Haven't encountered any issues in RTL pages while using:
.skip {
left: -1000px;
position: fixed;
speak: normal;
top: -1000px;
voice-family: female;
}
see http://ww3.co.il
Thanks for your thoughts
I work most of the time on RTL website... Hiding contents is really an issue and a pain in the ass
I try to set that particular element to { direction:ltr; } to get it to work correctly
Browser vendors should really do something about it
I'm still a big fan of
It's short, sweet and hasn't caused any issues in my experience.
I've been using the same method as Aaron Gustafson above for years and have never had an issue either... Are there any drawbacks that you know of ?
Aaron/Brent: The problem with
left:-999em
is in RTL interfaces. It forces a horizontal scrollbar. Which means that you'd actually have to swap it forright:-999em;
. If you don't have to worry about RTL interfaces, then you'll be fine.Right. When I've had to deal with RTL (like on CharterForCompassion.org), I've usually set an "rtl" or "ltr"
class
on thehtml
element or gone with the value ofdir
and then swapped out left for right depending on the situation. One thing worth noting to anyone doing that: if you set a default of left, make sure you setleft: auto
in the RTL version.I trying to hide the "Browse" (file) button for file attachment. Its working well in all browsers, but if I switch to other language OS like Chinese/Japanese, browse button area is not clickable.
Anybody face & fix this same problem?
This is a good article. Just Keep it up! Thanks!
This is a good article. Just Keep it up! Thanks!
This is a good article. Just Keep it up! Thanks!
Like Joshua up there, I too would just use display:none. I've been using that for accessibility for years. Any particular reason it wasn't considered for this project either?
As someone who was heavily involved in this discussion for Drupal 7 I'd like to just quickly pipe in to say that I don't think we've had any reports of problems with this approach that I am aware of since the launch in January. They would appear here.
I'm not suggesting that Drupal has the perfect solution, but a great many issues were considered in this thread. And it seems to be working for most users so far.
Ultimately the problem lies with Assistive Technology & the lack of an agreement on standards. If we could get them all to agree on a common behaviour for any set of code, we'd be so much further ahead. As it is there's a lot of guessing & endless testing involved.
Glad to hear that there are examples with simpler left: -1000px; based solutions working in RTL environments. I don't know how universally this would be.
Joshua & Janice - Most screen readers respect display:none and won't read out the content. This is certainly the case in VoiceOver. However, you can always test it with free tools like VoiceOver, NVDA or Orca & let me know if I'm wrong.