You want to hide something on a page, so:
.hide {
display: none;
}
But wait! By applying that class to an element you’ve immediately made that content “inaccessible” by screen readers. You’ve probably known this forever, but still, the poison apple sneaks into our code once in a while.
I don’t want to re-hash all the specifics. Your best bet is to read “Now You See Me” by Aaron Gustafson on A List Apart to get an understanding of this if you don’t already.
One way to encourage yourself to do the right thing is by creating more appropriate class names. Your regular hide class should position the content off screen, which still leaves it screen reader accessible:
.hide {
position: absolute !important;
top: -9999px !important;
left: -9999px !important;
}
I use !important
here because if you’ve gone to the trouble to add a “hide” class to something, you probably mean it and don’t want to think too hard about if the specificity value is strong enough. And if you know that you need to display: none
something, the class should help you understand it:
.remember-this-will-NOT-be-read {
display: none !important;
}
Another option for accessible hiding comes from some Snook research and the HTML5 boilerplate:
.visuallyhidden {
position: absolute;
overflow: hidden;
clip: rect(0 0 0 0);
height: 1px; width: 1px;
margin: -1px; padding: 0; border: 0;
}
OK you got it. Easy peasy when you’re totally in control of class names and all you do is apply and remove them. But things get a little tricker with JS libraries that apply their own CSS. For instance in jQuery, after you .slideUp()
, you’ll have a display: none
in the inline CSS to deal with. Yes, screen readers run JavaScript and yes, that’s still a problem.
Again Aaron Gustafson has us covered there, who suggests applying the accessible class name after the sliding is done and then removing the display: none
by sliding it the other direction.
var $button = $('#myButton'),
$text = $('#myText'),
visible = true;
$button.click(function() {
if (visible) {
$text.slideUp('fast',function() {
$text.addClass('hide')
.slideDown(0);
});
} else {
$text.slideUp(0,function() {
$text.removeClass('hide')
.slideDown('fast');
});
}
visible = !visible;
});
Here’s a demo of that:
See the Pen Hiding with jQuery by CSS-Tricks (@css-tricks) on CodePen.
Now we have the tools we need to stop using display: none
and start using more accessible “hiding” methods.

FAQ pages
If you’re hiding the answer until the question is clicked, hide with an accessible class name. Careful you don’t .hide() and then slideToggle(), that’s not good enough!

Labels
It’s tempting to use placeholder
text as a label replacement (especially now with some browsers improved UX of leaving the text until you actually type), but don’t display: none
or remove the label
s. I recently heard a heartbreaking story about a blind girl trying to apply for college and the form had missing label
s so she had no idea what to put in what fields. So if you’re going to use placeholder
text as a label replacement, use an accessible hiding technique for the labels.

Tabs
Just because a panel of content isn’t the “currently active” one doesn’t mean it should be inaccessible. Hide it with an accessible hiding technique instead. Or, you may not even need to. If all the panels are the same height, you can just flip-flop which ones is visible by adjusting z-index
.

@media queries
Turning on Voice Over in OS X and using Safari is a screen reader. Now imagine that Safari window was open to a very narrow width and the page had some @media queries for handling smaller viewports. And say that @media query hides some things with display: none
in order to better visually accomodate the space. This could be good or bad for accessibility. Are you hiding a bunch of crap that isn’t important to the page? Or are you hiding useful things that a person using a screen reader should have access to like they normally would.
No Expert Here
This entire post is based on the premise that display: none
is bad for accessibility. It’s not based on my deep and thorough understanding of screen readers and general accessibility. If you have more to add, things to correct, or personal experience to share, please do.
I had no idea of this, great article!
It’s too bad that things like placeholder aint implemented in the spec a better way, we’r lucky to have the gurus to point out this problem with a solution. I guess we’ll have to wait a long time before there will be a own css attribute for this, should be display: screenreader; or something.
Too bad there isn’t some type of media query for screen readers where you can just switch those values to block.
There is some edgecase problems with using:
top: -9999px;
left: -9999px;
http://snook.ca/archives/html_and_css/hiding-content-for-accessibility
the H5BP has a helper class that does just that
https://github.com/h5bp/html5-boilerplate/blob/master/css/style.css#L260
Ah yes! Thanks! Added that to the post.
But display:none; is such a useful property!!!
Yes it is, no doubt! And that is the purpose of this article! To discuss the dark side of misusing it!
Why would you hide things and still want them to be read? Sounds like a contradiction in terms to me.
Regarding the tabs example, instead, why don’t you make sure the tabs are keyboard-accessible (so don’t just add a click handler, use/make focusable elements for the tabs, and add keyboard handlers for it, and check that your tab order is sensible). Add some WAI-ARIA roles and modern browsers and screenreaders should be able to use them just like sighted users would.
This touches on a more important point: don’t assume ‘screenreader users’ and ‘normal users’ covers everyone. If you’re using hover only to hide/display content, you’re already doing it wrong (and how you hide the content is less important than making sure people without a mouse can unhide it).
I agree.
What’s the purpose of hiding something but not really hiding ? I never see a screen reader and maybe there is a reason of this but for me the problem is more how to unhide something on screen reader
Headings for major content sections to create a fuller heading hierarchy for non-ARIA-aware ATs, for example, Gijs?
Skip links? (Though only on large screens should they ever be allowed off-screen.)
To name just two.
And Vexal, if you have never even seen a screen-reader (or, I assume any other AT), then you really need to try one. There is no excuse for any front-end developer not bothering to spend just a little time using NVDA, Orca, VoiceOver, or even an evaluation version of JAWS.
“Why would you hide things and still want them to be read? Sounds like a contradiction in terms to me.”
I’m guessing this is faux naivety to make a point?
People hide things in interfaces so they can be shown as a result of some user interaction.
Ade: good examples. The rationale for those examples, however, is to have extra content for screenreader users which is hidden for normal users. That isn’t the case for the examples in the blogpost
Dave: Faux naivety — no, serious question. If you’re hiding things to re-show after user interaction, then just make sure screenreader users can show them like anyone else. Most have JS support; if they do not, they should (for the purpose of these particular elements) be treated like anyone else with no JS, and the content should probably not have been hidden in the first place.
another aspect of this is, that elements, to which
display: none;
is applied, are excluded from the dom- loading process.this is impractical, if one binds a load-event on a non-displayed inline-image or one wants to get the dimensions of an elemens, that isn’t displayed.
Спасибо, очень интересный обзор, но из него вытекает немалый объем работы по переписыванию script`s и css`s.
Exactly my thoughts!
Google translation:
Thank you, very interesting review, but it implies a considerable amount of work to rewrite the script `s and css` s.
If you’re hiding text on an FAQ page with the intention of showing it with JS, you should also hide it with JS, otherwise, people using regular CSS enabled browsers but with JS disabled JS will never be able to see the text, leaving you with an unusable FAQ’s page!
Excellent point. Remove it (visually) once the DOM loads.
Not to derail the discussion but why are one-liner comments so high in this site?
A nice option for this is to hide things that need to be hidden that way with CSS, but under a class set by js like:
CSS:
.js .visuallyHide {
position: absolute;
overflow: hidden;
clip: rect(0 0 0 0);
height: 1px; width: 1px;
margin: -1px; padding: 0; border: 0;
}
JavaScript:
$("html").addClass("js");
Thank you, Chris, reads like this bring the web forward :-)
Cheers!
the HTML5 placeholder wasn’t meant to replace the labels. It’s more to give an example of what is expected in the field> For example:
Email address : [email protected]
Telephone: (000) 999 9999
Very good point!
If you’re using less/sass you don’t even need to add to .hide (I use .hidden) class in the html, but you can use them as mixins. It saves you the trouble (and unpleasant feeling) of using !important and you don’t need back-end changes later on if the design changes.
As for not tabs and keyboard access, this won’t really help out screenreader users. Display:none is bad practice, it’s a shame jQuery and others are so reliant on it.
What makes you think tab/keyboard access is of no help to screenreader users?
Unfortunately this is a sad truth. Another sad fact is the lack of standard screen readers. For example label, even with display: none, it reads in Jaws (for windows). But it is a point to take care. Thanks
Simple, direct and very enlightning! Thanks!
Don’t make the possibly false assumption that screenreaders don’t ‘have’ javascript.
There’s a chance that the screenreader is reading the screen over the top of the browser. It makes sense to hide something using display:none in that case (with javascript), as in your FAQ example.
The browser can tab into the FAQ question, read it, then hit enter to open up and (and using #anchors) leap to the start of the answer. If they don’t want to see the answer, they’ll move on to the next question in the list, rather than having to read *all the questions* and *all the answers*, as would happen if the .hide answers are pushed off-screen.
Note – if you really like, set the item to display:none by default, then immediately overwrite it in a file called e.g. noscript.css. Use javascript to remove the noscript.css file. This would avoid and display of all the open items, before js kicks in on DOM ready.
This is a great example of how thorny web development can be. You might spend your time ensuring that your content is accessible to screenreaders, just to make it annoying for those folks to actually interact with your site. I believe it was Roger Johansson (456 Berea St.) who pointed out that just because someone is using assistive technology doesn’t mean they don’t want to have the same browsing experience as everyone else.
Personally, I use the .no-js / .js classes (w/Modernizr) to ensure my content is accessible to those without JS, while still providing a pleasant user experience to those with JS, and then I use .visuallyhidden classes for any “helper” text for screenreaders.
In my case, hidden text is a useful tool to accessibility. Here in Brazil, screen-reader users appreciate when we tell them where they are and how that content is showing.
For example:
I normally use h5bp.com‘s visuallyhidden class to hide this kind of text because it is obvious to “normal” users and a welcome information to screen-reader users.
PS: I’m still trying to figure out how this affects SEO though.
Great post. Just starting to learn about accessibility, so I found this very informative.
Rather than setting your “hidden” class and executing the reverse of whichever jQuery animation got you a “display:none,” wouldn’t it be better/easier/more efficient to either just remove the style attribute or use the .show() method?
This is what I was going to ask. Why animate something that you’re not going to see animate? You could just use hide() and show(). I guess that if you were needing something that those don’t do, you could extend jquery and create something like: .readable() which set everything you needed set, without animating something you weren’t going to see change.
Also, maybe you could update the way .animate() behaves at the top of your document, to accept a {readable: true} paramater? You could set it up to even be passed down from things like slideDown, allowing you to instantly cover accessibility.
Thanks for including the examples, they were extremely helpful.
I always thought that using CSS with top: -9999px; is bad SEO. Basically, spiders assume you’re hiding SEO’d content on your page but not wanting it viewed as part of the site. For example, you could throw a bunch of keywords in a div and hide it off the page. If the crawlers find a div positioned like this it’ll lower your ranking.
I feel like the problem is more with screen readers and less with the way things have been designed to be coded…
That’s a not-very-well considered comment. Screen-readers and most other ATs, are supposed to respect display:none (form mode excepted) because of its primary purpose. And besides that, ATs that rely on the accessibility layer are at the mercy of what is in that layer.
Thanks for the post. Good information. Joe, I used to think that, but the key is your intent in hiding the text. Read what Google says about this on Google Webmaster Central.
The problem is how do Google crawlers define your intent? I wish that article you linked made it clearer. This is what it stated: “If your site is perceived to contain hidden text and links that are deceptive in intent, your site may be removed from the Google index, and will not appear in search results pages. When evaluating your site to see if it includes hidden text or links, look for anything that’s not easily viewable by visitors of your site. Are any text or links there solely for search engines rather than visitors?”
And then it ends with “If you do find hidden text or links on your site, either remove them or, if they are relevant for your site’s visitors, make them easily viewable.”
I may be interpreting it wrong but this article seems to clearly describe hiding content so that it’s not easily viewable. He literally has a class called “visuallyhidden.”
As far as I know Google doesn’t parse anything in an element with “display: none;”. However, it does parse content with a “left: -999em;”. When it parses the former it won’t affect your SEO but when it parses the latter it will scan the content of the element and see if you’re trying to game their system.
I may be wrong but that’s my current understanding.
Here I found a blog articles (a bit dated) about this concept:
http://luigimontanez.com/2010/stop-using-text-indent-css-trick/
http://maileohye.com/html-text-indent-not-messing-up-your-rankings/
Obviously things may have changed and they don’t seem to offer ways around the problem besides media queries. I still avoid hiding things off-screen in this manner.
One last response by me.
It seems that you’re correct for the most part. Sites utilizing this technique will only be marked by Google–not penalized. If they discover further SEO spamming on your site the hidden technique can be used to penalize your site further, however, the technique alone is not enough to damage the SEO of your site.
Like you mentioned, intent does matter. But without Google releasing their algorithms it seems we never really know what will does what without trial and error.
Thanks for this post. I’m just about to start a few sites that most likely the users are going to be using screen readers and this has helped a lot…Thanks
Always good to remind developers that display:none makes content inaccessible to screen readers. It’s often misused, albeit unintentionally.
Still, there are many cases where display:none is the appropriate way to go. Screen reader users generally expect the page’s content as provided to them to represent the actual page content as displayed on the screen. Also note that not all screen readers are blind.
Additional content like headings or explicit form labels positioned offscreen where these serve to help screen readers programmatically offer users a better understanding of page structure or relationships are totally fine, should they be superfluous visually. However, in other cases, for example, unselected tab panels, I’d argue that display:none is what’s required.
Properly implemented tabbed interfaces are familiar to screen reader users who have an expectation of their functionality. In that familiar presentation, only the currently selected tab panel is available to the screen reader, or any user for that matter. This is part of the tabbed interface having a ‘state’: when the second tab control is active, only the second tab panel is available. When all tab panel content remains accessible, even if positioned offscreen, not only will a screen reader announce all of it, making a sighted screen reader user wonder what content is being read as it’s not visible on screen, but it will not be as clear to blind screen reader users what tab control is currently active, since all tab panels are available. And if the tab panel content positioned offscreen contains focusable elements, these will remain in the keyboard TAB order, adding additional but effectively invisible TAB stops, but when they gain focus, this focus will not be visible on screen, thereby affecting and possibly confusing all keyboard users, visually impaired or not.
Here’s one good article addressing this general issue: http://simplyaccessible.com/article/better-for-accessibility/
Cheers
Derek Featherstone’s article you linked to, Jason, was the exact reason I wanted to comment. Glad to see you’ve beat me to it! :-) It’s a good intro to why sometimes display:none is appropriate and sometimes not.
If you think about using z-index, don’t forget the maximum value of z-index!
Question: Why do you want to make hidden content available to a screen reader in the first place? If you “fade out” some content after a user action, why should it be available to the screen reader since it can’t be seen by a regular user? We’ve made the content redundant, why is it still needed? It looks to me like a over-thought solution for a non-existent problem.
OK well that is pretty important !
I use it with multilevel menus pure css with css3 transitions.
The WAI-ARIA spec specifies a hidden state which should be used and has a few very important points about visibility in accesssibility:
Chris —
Excellent points and extremely relevant. So often unless our clients require it or a target demographic need it to use a site, we forget these important things.
For those who are looking for a good Screen Reading emulator, Firefox has a great add-on called ‘Fangs’ (based on JAWS) here: http://bit.ly/io5aks . We’ve been using it to see what the reader will spit out and it’s been really helpful.
Thanks for the post!
I read comments about designing for people who disable Javascript all the time. Does anyone really disable Javascript on a modern computer using a modern browser?
Apart from the many users of NoScript, I can only comment for myself. If I’m using Firefox, yes, JS is kept disabled except for a whitelist. Otherwise, I use Dillo on Linux. In both cases, the primary reason is usability/accessibility issues.
very informative post. i’m just learning about accessibility and how to design and code websites accordingly. thanks for the post!
Wait, can’t you just use
???
To ATs, that behaves the same as display:none, because of their use of an accessibility layer. So would be fine to use when display:none is also appropriate, if you want the effect if vis:hidden, but if you need something to remain accessible, it won’t be.
Thanks for the info, will be taking it for a test run and playing with it.
It is sad however how the disability guidelines have been sidelined over the years and eye opening to see the consequences of it all.
Thanks for the article.
Makes sense, whilst we were designing out new recruitment system we tried to cater for screen readers. I’ve never used so many title tags in my life!
Good read, I never put much thought into this. I’ll use it in this manner forward for additional accessibility.
Cheers,
Chris
working at an agency, most of our clients could care less about accessibility, as long as it works on tablets and phones, and often not even that. it’s all based on how little they can pay and still get what they want from us. this kinda thing would never be paid for, but it’s a good idea. still, i don’t see a point in showing screen readers something that you want to hide.
You don’t? Have a read through the other comments: the point of creating content for ATs (not just for screen-readers) has been covered.
And if clients were not prepared to pay for a respectable basic standard of accessibility, I wouldn’t have a business.
What a pain in the behind this trick is, but I have to say The Filament Group wrote a great article on hidden elements that included discussions on using ARIA attributes. There is also a good reference to some of the pros and cons to the 4 principles outlined by the WCAG that must be met to ensure content is accessible.
http://filamentgroup.com/lab/expand_and_collapse_content_accessibly_with_progressive_enhancement_jquery
I’ve started using this technique just a few weeks ago… it finally hit me!
I have thumbnails of posts on the home page of our blog and used to display only the thumb… but now have it set to display the thumb, title, and excerpt and have those hidden off the page so that you have that content within the code.
Are you saying that if content is hidden on initial page load with display:none;, that it will never be able to be read by screen readers, no matter what changes happen to the DOM after page load?
It’s not really about the DOM, since few ATs (and no screen-readers, IIRC) access it directly: it’s about a browser’s accessibility layer and disp:none is supposed to keep elements out of the layer.
And I forgot to add that the element should go into the layer if disp:none is removed, though it’s often the case that the change won’t be picked up by the AT unless ARIA is used (and it’s ARIA-aware).
Good information Chris. I’ll be sure to make a note of that if I’m risking losing quality content, but I’d argue that rather than us nitpicking the code and increasing our workload, that we simply produce hordes of great content (enough so a few display:none’s don’t cloud anything) and let Google sort out the good sites from the bad ones.
What’s up with my portfolio tut? :)
Thank you for the great article Chris. In my current position, I have to make sure that our site is accessible and 508 compliant. We do not use display:none; but rather using the technique you have described to hide the content off the screen.
In addition to making content accessible, the other half of the equation is that we need to make sure the site is usable. Meaning, the reason you might hide content is because you want to add and hide a link that skips the navigation and anchors to the main content of the page.
Why? Imagine using a screen reader and having to tab through a header with a few links, and then the navigation with many links, and maybe a small set of social media links, that’s a lot of content the user may not need. But if they land on the page, and the first link they can hit says “Link to skip to main content”, it lets that user skip “useless” content and go to what they want, the main content on that page.
Those not using AT take for granted we can just look and click to get what we want.
And yup, Fangs for Firefox is great way to simulate what a screen reader outputs, and if you are inclined, take a look at FireEyes for Firefox, it’s free (not a spokesman!).
woh ! very important thing . i will keep this in my mind . Thanks for share :)
Using negative offsets still creates a huge box that needs to be rendered off-screen.
A faster way is:
.hide-text {
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
}
Via http://www.zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement/
An addition about the naming thing: “.visuallyhidden” is way too long for me. That’s why in my projects I renamed the “.hidden” to “.away” (because it’s physically not there anymore) and “.visuallyhidden” to “.hidden” (because it’s… well… hidden outside of the viewport).
I used display:none so many times. I wonder if there’s a way to use server-side scripts (php) for that.
My concern is not just to hide the element but also not load it if it’s hidden. For example, on a mobile device stylesheet, I hide certain elements that show in the desktop view; and at the same time I don’t want them to load on the mobile version because it may slow down the page a little. Any ideas?
Screen readers are pretty much up there with ie6.
That is one of the most crass, ill-informed, and wholly inaccurate comments here.
It’s quite informed, but not what you want to hear. I’m pretty sure the share for sr is so low it’s not even worth going into so much trouble to satisfy a few. If you digress I’d like to see some real stats that prove otherwise.
If you have used any AT, you know that most of them, particularly screen-readers, are more sophisticated than any browser, most of all IE6.
It takes very little effort to build AT-friendly websites. Just some knowledge, empathy, and thought. Things that all developers should possess. There is not much that can excuse not knowing basics like this particular topic, which has been written about so many times for years now.
If people want user data, they can get it from any national body that represents disabled people. But to try to reduce disabled people like me to mere statistics is unproductive, uncaring, and quite offensive. And such data is largely irrelevant because we all can and should build websites that are usable by everyone who can use the web. If someone can use website A, they should also be able to use the similar website B, because it can be build to the same standard. Whether doing that accommodates an extra 0.1%, 1%, or 10% is orthogonal in the context of inclusion and must never be used as an excuse for not ensuring a reasonable standard of accessibility. Or doing one’s job properly, to put it another way. Developers should not complain about doing some very simple things that make a vital difference to some of us.
great points, and tutorial. Another thing people don’t think about is that display:none and visibility:hidden get your code to come up in malware scanners, the same as gzip, eval, and base64 decode statements. Good to hear there’s another (or better) way to do the hidden code thing.
Thx for the blog post!
What is the different effect of using either in terms of being penalised for ‘ghosting’ content?
It is a very much informative right to the point article with some good resources. Thanks a lot for sharing.
Note that
display:none
is not always bad regarding a11y.For example, it can be used with complex menus a la drop-down or fly-out.
That’s because using
display:none
(vs.position:absolute
with a negative offset) removes elements from the tabbing flow which helps users navigate through very long menus… and the page.display:none; is still useful for elements that are not necessairly readable…
What’s wrong with visibility:hidden ?