Journal
Show / Hide Solution
28 July 2006 › 19 comments
Update: I no longer recommend using this solution. Instead, I would suggest the document.write() method as described by the article on QuirksMode.
This solution arose over a lunch at Jack in the Box with my former coworker, Cody Lindley. We pondered if it would be possible, and I decided to find out. The following has nothing to do with Ajax, so don’t bookmark it as such.
The Problem
With the increase in standards compliant JavaScript support in the past few years, there have of course been more and more effects libraries springing up. This has led to people using hide / show methods with confidence that they will work on a variety of operating systems and browsers. One of the most common effects I see is content appearing, seemingly out of nowhere, when a link or button is clicked.
While this is all well and good, something that is often overlooked is what happens (or doesn’t happen) when JavaScript is either disabled or for whatever reason unavailable. This is typically caused by content being presented within the HTML, but hidden with CSS, which is subsequently over-written by JS, causing the content to magically appear.
An alternate method is having the content load as visible in the HTML by default, but then adding a CSS style with JavaScript as the page loads in order to hide it. Often times, this creates a momentary point of confusion on screen, as the DOM tree is created, and then hides the specified nodes. Because of this unsightly bugginess, some people tend to err on the side of visual consistency rather than accessibility.
Possible Solution
Well, I got to thinking: Why not hide things with CSS by default, but then provide a contingency plan with noscript for those situations in which JavaScript is not available? That way, there is no funky screen flickering as the page loads. Plus, in situations where the client is not surfing with JS on, the content just starts out visible by default, and we hide the hide / show controls altogether. After reading this article on Maratz.com, I had an idea.
In his example, he uses noscript to provide a header when Flash and/or JavaScript were not present. I have taken that a step further, and put noscript directly in the head of the document to be able to specify alternate, over-riding CSS styles when JavaScript is not available. Arguably, this is breaking with convention because the W3C validator throws an error.
However, after reading the spec, I could not find where it specifically said not to use noscript in the head. It stands to reason that if script is allowable, then noscript should be too. Using that basic logic, and adhering to the principle set forth in the Noscript Spec, I think this is a viable solution…
The NOSCRIPT element allows authors to provide alternate content when a script is not executed. The content of a NOSCRIPT element should only be rendered by a script-aware user agent in the following cases: The user agent is configured not to evaluate scripts. The user agent doesn’t support a scripting language invoked by a SCRIPT element earlier in the document. User agents that do not support client-side scripts must render this element’s contents.
According to that definition, the way I’m proposing noscript be used is perfectly legitimate. Despite that, the validator has a little problem with it. However, given recent dissention with the W3C process and validator, voiced by Zeldman and Hoehrmann, I think that perhaps we should err on the side of usability and accessibilty as opposed to some automated checklist.
In fact, there was an entire panel at SXSW, entitled Standard Deviation (podcast here), devoted to discussing situations in which not using web standards are actually in the best interest of the end-user. I think that this could possibly be one of those instances, but I am really not sure.
This has been tested in the latest builds of Firefox, Internet Explorer, Opera and Safari. I also tested it with Fangs, the screen-reader simulator extension for Firefox, and it works just fine – giving two different sets of content based on JavaScript being either on or off. As an aside, I found it very weird that Fangs puts “dash Internet Explorer” in its reading of the browser’s title bar.
The Example
So, all that being said, here is the example: Show / Hide + Noscript. Do with it what you will, depending on if you think the validation issue really matters. Also, I’d be curious to hear what you guys / gals have to say about the issue at hand. Is this an acceptable use of the noscript element?
Discussion + Dissension
Comments closed after 2 weeks.



#1 Justin Perkins
You’re missing a type=”text/not-javascript” on that noscript tag!
:)
On a large site that had lots of show/hide type stuff, I think this would be a little hard to keep under control, but for personal sites I’d say it’s perfect.
#2 Elliot Swan
I think it’s a great idea. I’ll admit that my love for sweet effects and script.aculo.us has caused me to often hide content with a “display: none;” causing some usability issues. I too didn’t want to use JavaScript to hide the content because of the delay, so I really like this…
As for the validation issue, I say who cares. Standards were created for two reasons 1) to ease development, and 2) to help usability. But sometimes the W3 misses things or the validator doesn’t include certain properties (i.e., CSS3), and we can’t let that get in the way of a quality user experience (which is really what standards are there for).
I actually wrote about this quite a while back: Standards and validation, what are they good for?
#3 Nathan Smith
JP: Nice, I’ll have to remember that one. It wouldn’t have to be hard to control for large sites. You could just as easily put a link to a CSS file, rather than have it hard-coded. I just did it this way for ease of viewing one source file.
Elliot: I agree too, that if it works cross-browser, sometimes it’s just easier on the client-side as far as usability to do things the “wrong” way – which is of course why innerHTML is so widely used, despite not being a W3C standard.
#4 Dustin Diaz
A simple and easy approach. This philosophy would be easy to put into place on a large scale site with a style sheet like you said. If you wanted a pure progressive-enhancement without using the ‘noscript’ tags, and without the fuss of getting that weird screen flicker when waiting around for the window ‘load’ event to fire, you could use something like Prototype’s DOMContentLoaded , or there’s definitely YUI’s YAHOO.util.Event.onAvailable which allows you to run a function once an element is immediately available in the DOM. It’s quite slick actually :)
#5 Justin Perkins
> It wouldn’t have to be hard to control for large sites.
I just mean with lots of different people maintaining the code and lots of different shown/hidden elements, and as Elliot pointed out scriptaculous requires you to use display:none right there in the style attribute (takes precedence over anything else).
It really depends on how accessible/usable you want to make your site and how much time you’re willing (able) to invest.
#6 Elliot Swan
Huh, I hadn’t seen DOMContentLoaded before. I tried out the domready.js method here: Show/Hide
Sure enough, there’s no flickr. Er, flicker.
I hadn’t thought of the fact that the display: none; in the style attribute will mess with the noscript method when using sript.aculo.us. I will say, that’s one thing that I don’t like about script.aculo.us…
But if you’re not using script.aculo.us and are using something like jquery, I still think the noscript is a fairly clean and simple way to do things.
#7 Sebastian Steinmann
What Opera version did you test it in? In Opera(9.01 build 395 on kubuntu) the image popps behind the text, but in Firefox(1.5) the image dont.
#8 Ara Pehlivanian
I’ve been using a document.write() in the head that writes the CSS link. I call the CSS file initial_states.css and I put all of the display: none’s, that would otherwise cause the content to be inaccessible without JavaScript support, in it. That way, if JavaScript isn’t supported/available, the CSS file won’t be loaded and all of the initially hidden content won’t be hidden. Works pretty well actually. The only thing is that it uses document.write(), but I’m sure it’s completely possible to do with the W3C’s DOM manipulation methods too. I just haven’t bothered yet. ;-)
#9 Jon
Really interesting technique, Nathan. Many times, the possibility of someone viewing a site without JavaScript support is overlooked by the developer. Hopefully this will increase the awareness for many up and coming developers and offer a possible solution for them. Good work!
#10 Nathan Smith
Sebastian: I checked it in Opera 9 on Windows and it seemed to work fine. Again, I’m not saying this is some miracle fix, just pointing out that it might be something to think about. I was actually surprised to find that it worked.
However, I’m thinking the way that Dustin and Ara do things is probably the better way to do. I just figured I would throw this idea out there, and see what everyone thought about it. At the very least, it gets us thinking more along the lines of accessibility when using JavaScript techniques.
#11 Justin Perkins
> I will say, that’s one thing that I don’t like about script.aculo.us…
Yeah I could see how that would bother people, but it hasn’t burned me yet. In a way, it makes sense though b/c if JavaScript is not enabled then you won’t see that additional content and your links that fire the show/hide could have a fallback solution that cause normal page refresh to occur (in which case you’d use server-side code to show/hide the element).
#12 Tom
Nice idea, the result is very good. I hope that things will change about w3c validation, your theory is right and I agree that using noscript tag in the head section should be permitted.
#13 Dan
It’s not like me to pick a fight, and I absolutely love the code that came out of this example. Although, what you were saying kind of reminded me of something.
Isn’t saying However, after reading the spec, I could not find where it specifically said not to use noscript in the head. kinda like saying “Well, God didn’t say NOT TO do this or that, so we’ll go ahead and do it.” ?
With that thought this kinda makes me a little cautious to implement, but then its my own opinion and I am free to come up with my own idea if I wish. ;-) Accessibility IS the key I believe so with that in mind, I think this is a great example and can see why noscript should be allowed in the head, then again everything in the head is very one directional. There is no nostyle tag or no notitle tag (hehe at least that I am aware of). So maybe the inclusion for the script and noscript tag counter part should be reworked? I’m not proclaiming, but just throwing it out there to see what others think.
#14 Daniel
Great little technique.
However, in Safari 2.0.4 I did find that your example will not show the hidden content until I first click on Hide then choose show. Once I have clicked on Hide all funcionality works as it is supposed to.
Just a heads up
#15 Nathan Smith
Tom: Yeah, it seems like it should be allowed anywhere that script can go.
Dan: Good point. After seeing some more clever ways of using the DOM before the entire page has loaded, I’m beginning to think that the noscript route might be a dead-end. At least, not for use in the head. What you said about nostyle doesn’t quite apply, as there is not a nostyle tag for use in the body, whereas that seems to be the very purpose of noscript.
Daniel: Thanks for the heads up. I guess it’s not so spectacular after all.
#16 Demozi
Thanks. I am getting points now. I will try these Ideas. Wheeww… thinking about that wiull be hard for me. But anyway, I will remember or if I cant i will just come back here. Thanks Man! Demozi
#17 Mithrill
Nice work Nathan and thanks again for sharing your vast knowledge. This script is so nice because I didn’t notice any flickering and it loads immediately.
#18 Vitalized
I’ve been looking for this solution for ages now! Thank’s for posting your great work.
#19 Zach Blume
Wow. Absolutely brilliant idea! I can’t beleive no one’s thought of it before, hehe.