Journal
Accessible Display: None
31 March 2007 › 47 comments
Update: According to accessibility expert James Edwards in comment #33, the screen reader Window Eyes has problems reading content that is contained in elements with 0 dimensions and overflow: hidden. I personally still prefer this method to others out there, but wanted to make readers aware of the potential drawbacks regarding this particular assistive technology.
At the request of another accessibility expert – Derek Featherstone in comment #37, I have uploaded a test example here: display_test.html.
From time to time, the necessity arises to have hidden content present in a page. In case you don’t already know, simply using CSS for display: none on the content will not cut it, because assistive technologies such as screen readers will treat this content as if it does not even exist in the DOM.
Many show/hide methods will allow the XHTML content to load, pre-hiding it via JavaScript using display: none and then re-showing it with display: block. This is a perfectly good method, and is accessible. I myself do hide/show elements this way, using Peter-Paul Koch’s proposed usage of document.write(). You can read about it at his site, Quirksmode.
Yet, what do we do about those fringe cases in which content needs to be present in a page, yet hidden with no intention of re-showing it dynamically? Obviously, if you are not going to be manipulating the element via DOM scripting, then it shouldn’t be used to hide said content in the first place. We could use absolute positioning, but that gets tricky if you are also doing multiple layers of complex z-index transparency within a design.
Example
A search form would be the quintessential example of where you would want an element hidden, while still leaving it accessible to screen readers. While most search forms are easy enough to recognize to those who are sighted, far too many lack the required <label for="x">Search</label> paired with an input. Without this, screen readers cannot associate the text field with its description, leaving blind users to inferences based on conjecture.
Consider the following demonstration. First off, we have the styled search form, with the label tag viewable. Below is the form’s code, in XHTML 1.0 Strict. Note, the span is there for styling ala Shaun Inman’s method.
<form method="get" action="#" id="search_form">
<p>
<label for="q">Search</label>
<span>
<input type="text" name="q" id="q" />
</span>
<input type="image" src="/img/search.gif" alt="Search" />
</p>
</form>
With no additional styling applied to the label, we get a the following visual output, with Search displayed in black at the default 16px sized serif font.

With visibility: hidden we have a conspicuously ugly space left behind.

However, by using some clever CSS we can achieve the same visual effect as display: none without the accessibility drawbacks. By doing it this way, we get the best of both worlds: lack of visual redundancy, while still being nice to blind users. This method is also search engine friendly, in case you are worried about Google rumors. Ideally, this is how we want it to look.

The code for this is really quite simple. By default, the label tag is an inline element, meaning that we are unable to style its dimensions. In order to wrangle it under control, we do something that might be considered counter-intuitive. We give it display: block so that we can set its dimensions, and then we use overflow: hidden to cull its contents.
#search_form label
{
display: block;
overflow: hidden;
width: 0;
height: 0;
}
I like to think of this method as fixing a piece of fabric when a thread is hanging loose. Just grab the other end of the strand and then pull it back through the cloth – Nobody is the wiser that it ever protruded.
Discussion + Dissension
Comments closed after 2 weeks.



#1 matthew smith
Nathan,
Clever. I’ll have to give that a go next time I need to do that. Now how about a write up about that search box :)
#2 Nathan Logan
Nicely done. I’ve been looking forward to reading about this since you showed me at SXSW. Very clever.
Actually, this example has helped me to overcome several other types of CSS problems in the last couple weeks, so thanks for the mind-opening.
#3 Ian
Thanks for the good article…
Off topic, but what’s with the new logo… I’m chuckling here – I’m sure it’s a jab at the recent logo fiasco?
DOH Just scrolled up to take another look… noticed april fools :)
good show, mate!
-Ian
#4 Mat
Thanks for the tip Nathan.
I’ve been using ‘display: none;’ for far too long primarily because I found the ‘text-indent: -9999px;’ practice of pushing content out of sight senseless.
#5 Nathan Smith
Mat: Yeah, the -9999px trick never seemed to make a whole lot of sense to me either. I always envisioned some crazy fringe case in which a guy would be browsing full-screen on a monitor with a 10000 pixel wide resolution, and somehow see the text poking out. I like having peace of mind.
#6 Andrew Ingram
Nice tip Nathan, it’s a method I’ve thought of using before but never really thought of a use for it. I had thought to use it to hide skip-to accessibility links but ended up deciding that all users should be able to use the links.
Doesn’t look like it provides a solution to the problem of hiding the text in image-replacement techniques though. I guess the javascript/flash methods are the most reliable for this particular problem if you want to avoid text-indent.
#7 Jon Christopher
A great technique, Nathan. Invisible elements that have significant importance are becoming an increasing problem in my opinion. This technique solves many of the issues other visibility techniques have a problem with — nice work!
Mat: I too dislike -9999px not only due to Nathan’s reason, but also due to the fact that if you’re using the technique on an anchor, the dotted border of many browsers extends awkwardly off the screen (without further styling).
#8 Nate Klaiber
Good article Nathan. I have gone back and forth with different methods. Absolute positioning, as well as -9999px. However, I have always been looking for something more ‘graceful’ and accessible. I stumbled upon this method a while back and have found it to work wonderfully.
Now if you could just solve the IR issues that Andrew mentioned – you could have the world at your fingertips!
#9 Jonathan E
@Nathan, Jon & Mat: Simply setting ‘overflow: hidden;’ will resolve all of the problems you’ve been worrying about with text-indent: -9999px;
#10 Julian Schrader
Great tip Nathan—thanks!
I think this will be of use for everyone around…
#11 Riddle
@Jonathan E: But you won’t be able to undo your click (mousedown, drag outside link, mouseup) on such styled link.
#12 trovster
I simply do the following, hich seems to do the trick just fine:
element, #id, .class { position: absolute; left: -9999px; height: 0.0; width: 0.0; overflow: hidden; font-size: 0.0;
}
Everything you’re worrying about text-indent: -9999px; is a little far-fetched. First of all there is the edge case you talk about — better support those edge-case browsers, and all other really obscure scenarios. Secondly, as Jonathan E mentioned, setting the overflow and a width (I’m talking about using this for image-replacement, as I use the code above for hiding) and the width of the element is less than 9999px (should be!) then you’re fine. Also, setting overflow: hidden; on image-replaced links solves the focus-halo extending to the side of the browser window in FF2.
#13 Nathan Smith
Trovster: That’s all well and good, except for when you’re already doing quite a bit with absolute/relative positioning, and don’t want to affect any of the layering. I specifically said that in the article, yet you felt the need to bring it up again. Simply put, that method isn’t as good as the one I’ve proposed. My way doesn’t re-position anything. It’s more simple and concise.
On an unrelated note – Riddle, you brought up a good point in response to Jonathan E’s comment – being unable to cancel clicking for image-replaced links with overflow: hidden. It’s a minor, but annoying accessibility issue.
#14 Paul Michael Smith
I will be using this for things like skiplinks, labels and the other such elements I think some people here are confusing this with image replacement but that is not what its for.
#15 trovster
Sorry, I fail to see how using the position: absolute; effects the design. Because I also set the height and width to zero. I also set the font-size to zero, as some browsers can take that height still (as IE6 treats height as min-height). Sorry for bringing up my suggestion and reasoning. Your method must be better.
#16 Nathan Smith
Trovster: It affects the layering of multiple elements that have position: absolute within a container that has position: relative. Believe me, there are real-world factors involved, else I wouldn’t have proposed an alternative.
#17 Nathan Logan
Paul – hadn’t thought of using it for skip links – that’s the perfect use. Thanks for the idea!
#18 Steve C.
I still don’t understand what’s wrong with what Trovster said, could I get a little more explanation about how an absolutely positioned div might affect layout in the page? You’re being a bit harsh on him here I think. As with all things CSS I’m sure there are multiple solutions here.
#19 Nathan Smith
Steve: It’s not layout so much as layering. If you’re already dealing with the z-index of multiple layers with absolute positioning, adding yet another layer can get be problematic (IE7 is especially finicky). Essentially, it’s not so much that there’s anything wrong with the old method. It’s more a question of, in light of a simpler way to do it, why advocate an antiquated approach?
You’re right though, perhaps I was a bit too harsh. I’ve just been dealing with a lot of negative blog comments lately, and I that has been wearing down my patience. Trovster, you have my apology – Sorry about that.
#20 Jonathan E
@Nathan, Riddle: Good point. Actually I was unaware that setting the overflow: hidden; is what caused the “unable to undo” problem. Do either of you have an explanation as to WHY it works this way? I’ve obviously run into this little bug from time to time, but I didn’t know it was because of using overflow: hidden;
Also, Nathan, I’ve noticed you’re using the text-index: -9999px; overflow: hidden; on your logo for this site, and in Safari, IE 6 and IE 7 I am able to “undo” my click on the logo. So is this strictly a Firefox issue or are there other browsers that handle this the same way?
I guess if it’s only a Firefox thing, it then begs the question of whether or not this is the way it’s supposed to work… which is the same question about whether or not the link “halo” should be so wide because of the negative-indent on the text.
Thoughts?
#21 Nathan Smith
Jonathan: Yeah, I’ve sort of put up with the no-click-undo problem, as I see it as being slightly better than the lasso problem. As for why Firefox does things that way, I’m not sure. One way to get around it would be to put a span within the link and then do the whole display:block/no-dimensions fix as described in this post, with display:block on the link plus set-dimensions. Of course, then the nay-sayers would point out that it’s extra, unnecessary markup. :)
#22 Jonathan E
Nathan: exactly… that’s why a lot of people (myself included) use the text-indent method more often — because it doesn’t require extra markup to achieve the same (at least visually speaking) results.
#23 Nathan Smith
Jonathan: Yeah, for image replacement I think text-indent is the way to go. I just don’t think it’s necessary if you truly are hiding content that you aren’t image replacing or showing later via DOM scripting. In those cases, I think the method described in this post is the most viable. It’s all about choosing the best possible method for the job at hand. In such cases, this is it.
#24 Jonathan E
Having said that, I don’t know that I’d put myself in the nay-sayers category. If it comes down to a choice between something that may cause serious accessibility and/or usability concerns and a couple of extra span tags here and there, the choice is obvious:
h4rdc0r3 standardista approachextra span tags to ensure optimal accessibility and usability.Exactly.
#25 Steve C.
Interesting, I didn’t know multiple layers could be finicky like that… I’m working on something now that does a lot of z-index layering so I’ll keep that in mind. Thanks!
Also I may have stepped out of line myself as I had just assumed those comment links were to Trovster’s previous comments on this page, and didn’t know of a history of negative comments here… I shouldn’t have gotten involved there, sorry. Just found this page off of the CSS Beauty link this morning :)
#26 Nathan Smith
Steve C: Yeah, I ran into trouble with z-index and absolute positioning in IE7 on a recent project, which required multiple layers of PNG transparency.
#27 Paul Michael Smith
Just used your display:none tip and it worked a treat, so thanks again fella.
As for Image Replacement I have not found a single solution that deals with all the possible scenarios. For example, they all seem to over-look the “CSS ON but Images OFF” scenario which I have seen in the wild.
#28 Michael McCorry
I think that this is a great tip. I’m not adverse to using the -9999px trick (although I tend to use -9999em, or even -999em which usually 40% larger than -9999px. I’d like to meet the person with a monitor that big :), but this tip will definitely have its uses, not just for hiding “skip to…” links, but also for adding extra meaning to some visual elements for accessibility purposes.
Jon Christopher (#7):
“I too dislike -9999px not only due to Nathan’s reason, but also due to the fact that if you’re using the technique on an anchor, the dotted border of many browsers extends awkwardly off the screen (without further styling)”
I know you said “(without further styling)”, but for those that don’t know, the CSS property “outline” controls this dotted border. Setting “outline: 0;” on your anchors gets rid of any dotted overhang when focused.
#29 Nathan Smith
Michael: Yeah, setting the outline property to a 0 value will keep the border from appearing, but when I originally proposed that method, a lot of people were quick to point out the possible drawbacks when it comes to accessibility. Namely, the user cannot tab through links with a focus border. Essentially, it makes Firefox every bit as inaccessible as Opera, which by default has no focus borders on anything. You can read that past discussion here:
http://sonspring.com/journal/removing-dotted-links
#30 Suzy
Very good indeed! Thanks a lot for great articles like that.
#31 Dustin Diaz
You’re meaning to tell me that this blog post could have been as short as just saying:
selector { display: block; overflow: hidden; width: 0; height: 0;
}
If you’re anything like me, I just stopped explaining things altogether… too much effort ;)
Btw, good explanation :)
#32 Heart
thx for the tip.
i just tried it with the extra div used to clear floats and now i don’t have this unwanted space that shows up on IE6.
.clear{ clear: both; overflow: hidden; width: 0; height: 0;
}
#33 James Edwards
I’m afraid this doesn’t solve the problem, it just re-creates it in a different way. The screenreader Window Eyes cannot see content which is completely hidden with overflow.
If you have partial visibility with hidden overflow, or scrolling overflow, then that’s fine; but if the width and height are both zero so there’s no rendered output at all, this is just as inaccessible as using display:none;
The offleft positioning technique is not perfect, because elements in the tab order are still in the tab order even though apparently hidden, and that can be a cognitive/usability issue to a sighted user.
But there’s no issue with layered content – you just put all the layers inside a single positioned element, so that element is the positioning context for everything inside it, and then move just that element off the page.
#34 Patrick Haney
Great find, Nathan. I typically use the text-indent: -1000em trick myself, but this seems to be a good alternative. I don’t know that there is a perfect solution, but it’s good to see people are looking for other ways to stay accessible with hidden content.
Have you tested this on a lot of browsers/screen readers? I’m just curious how universal the experience is.
#35 Toby Davies
There are literally dozen of methods for hiding elements on web pages. For instance, I’ve been using the following class up until now …
.Hidden { position: absolute; height: 1px; margin: 0; top: -1000px; left: -5000px; overflow: hidden;
}
.. which is pretty similar to the method mentioned already but also positions the element way off screen to the top left.
However, a word of caution … there are rumours going around in SEO cirlces that Google has started to spider external CSS files and is developing an algorithym that can identify “hidden” text. According to Google rules any form of “hidden” content that is not visible when viewed in a standard browser is considered spam.
Lately I’ve had to go through a lot of old sites of mine (I work for one of the UK’s leading ecommerce companies) and remove any “hidden” text, even if it’s in there for perfectly valid accessibility reasons. I’ve really argued my case, but a lot of our clients have been getting third-party SEO companies to provide reports on how they can improve their Google rankings and “hidden” content keeps coming up as a major fault.
Apparently this also includes the text-indent method that is often used for replacing text in buttons or links with a background image that says the same things, but uses a nicer font.
I’m not too keen on designing/coding for Google, rather than the end user, but at the end of the day if you’re a commercial company the most important thing is to get visitors to your site in the first place, and most web traffic is now coming via Google.
From now on I’m basically taking the approach that if I want to have a bit of text in a page for accessibility reasons it’ll have to be designed in a way that it stays visible.
Whether these rumours prove to be true or not, time will tell, but you might want to consider it and be ahead of the game.
#36 George Smith
Would it be possible to only use height:0 for this, leaving the width intact. thus stopping the Windows Eyes problem?
You could then do the opposite if you needed the width taking out instead.
#37 Derek Featherstone
Nathan – I think it is important when you’re putting together examples like this to provide a stand alone file that gives an example. I’m very keen on testing this. Do you have a file/example somewhere posted online?
#38 John Faulds
@Toby Davies: adding the CSS directory to your robots.txt should prevent search engines from spidering your stylesheet and thus imposing any penalty on what it finds there.
#39 steve faulkner
i thought that I had posted this comment the other day, but it apears to have disappeared or not appeared in the first place, anyway here goes;
An alternative method to provide a explicitly associated labels for form controls, in cases where visual display is not required, is to use a title attribute on the input element . The title attribute on form controls is announced by default, by screen readers if there is no text label. (note: the title attribute is not announced by default on links).
#40 Rakel Svensson
Thanks for this great article! I’m using your ideas at expressn.
#41 Michael Montgomery
Nathan,
Thanks again for another useful technique.
I’m using this, in combination with the usual negative text-indent for image replacement.
One question for the experts: I had some tabular data with a header row that explicitly named the columns, which were obvious to people viewing the visual design. To use this accessible display:none on the header row, I had to add margin: 0
(Might be obvious, but it took me a while to fix it.)
Are there other situations that might also require resetting a margin or padding?
#42 Michael Montgomery
...and maybe also, for good measure: line-height: 0;
#43 Nathan Smith
Michael: There could possibly be situations in which zero-ing out the margin might be necessary, depending on what properties are inherited. As for line-height, if you set it to 0, it’s not valid. Sometimes, if I need a div purely for presentation, or I am worried about resizing text messing up a layout, I will give that font-size: 0. It seems to do the trick.
#44 Matthias
Thanks for that great technique!
I read it yesterday and – surprise – today I need it in a project!
I have a table with a caption tag for usability, but I don’t want to show it and with your approach I can hide it and the screenreaders will interpret it also.
Very nice.
#45 Nathan Smith
Matthias: Hey, glad it is helpful. Nice site by the way. I wish I was able to read German, but alas I am not as multi-lingual as I’d like. :)
#46 Klaus
This does not work with IE 5.5, but with 5.01 and IE 6.0/7.0. Only IE 5.5 is making trouble. I’ve fixed it with Conditional Comments…
#47 Nathan Smith
Klaus: Thanks for letting me know about IE 5.5. I don’t really bother testing in that version of Internet Explorer anymore, especially not since Yahoo dropped it from their A-grade browser list – YUI Graded Browser Support.