Enable JavaScript specific CSS with one line of jQuery
jQuery is by far my favorite JavaScript framework in terms of simplicity and just pure DOM power. I picked up a little trick at a conference quite a few months back and improved upon it and thought it could benefit anyone that believes in the mantra of progressive enhancement. Here's the line of code that will change the way you develop your applications.
$("html").removeClass("nojs").addClass("js");
Obviously jQuery is a requirement here. The other thing you'll need to do is add a class of nojs to the html node of all of your documents/templates.
<html class="nojs">
Now you're ready to change the way you write your CSS. I'm aware that Yahoo/YSlow recommend that you stick your JavaScript at the bottom of the page, but this little trick won't work as well unless jQuery and the snippet above are in the head of the html document. Now what this buys you is the ability to style your document with separate elements for javascript enabled users, non-javascript users and common elements that both will need. You'll be able to hide/show substitute elements in the page that are dynamic in nature so that you can successfully implement a site using progressive enhancement, meaning that users with javascript disabled will still be able to use your site but without all the bells and whistles. This also prevents the flicker that you see on page load when you modify elements via DOM manipulation using JavaScript.
Now you can write CSS like this:
.nojs a.myclass {color:red}
.js a.myclass {color:black}
a.myclass2 {color:blue}
In this very simple example all of your non-javascript users would see links with a class of myclass as red and all javascript enabled users would see the links with the color black. Both javascript and non-javascript users would see the links with the class myclass2 as blue.
This very simple example opens hundreds of possibilities for the way you style your site. You could actually display and hide content based on whether javascript is enabled or not, including buttons and links or any element on the page. You could include text for Search Engines and Screen Readers that your regular users might not need to see because the nature of the content could be for SEO or descriptive purposes for non-javascript users. You could also use it to enhance your suckerfish CSS menus with a hoverIntent when javascript is enabled making your menus a little more user friendly.
I realize this technique could be implemented with just about any JavaScript framework, jQuery just happens to be my framework of choice and this technique has definitely given us much capability to target javascript/non-javascript users and unobtrusively progressively enhance our website.
Please see my latest article on implementing this without a JavaScript framework.
April 22nd, 2009 - 22:14
Nice post! Reminds me of one I wrote a while back. I don’t think you really need the “nojs” class, though. It would be simpler to have a.myclass {color: red;} and .js a.myclass {color: black;}, and the result would be the same. Also, as someone pointed out in my article, this can be written quite easily without any JavaScript library:
document.documentElement.className = ‘js’;
Also, if you’re using jQuery, it’s important to keep this outside any document ready handler and preferably call it in the head of the document.
April 23rd, 2009 - 08:00
@Karl,
Thanks for the comments. I actually find a lot of use for the nojs class, it’s the improvement on the original design I was speaking of, and I’m planning on writing more about techniques using the nojs/js classes that otherwise wouldn’t be achievable. You look familiar, I’m pretty sure it was you speaking at the Ajax Experience last year that caused me to originally implement the js class. I’ve used it on one of my sites to make my suckerfish menus operate in a CSS-based manner when no javascript is available, but when javascript is present I use the hoverIntent plugin to make my menus a little more user friendly (not have menu soup while the user is moving around the page). We’ve also used the nojs to expand accordions when javascript is disabled and to include or not include icons that represent dynamic functionality. Your comment got me thinking and it might not be a bad idea to implement without jQuery , like you mentioned you could just add document.documentElement.className = ‘js’; into a script tag at the head of the document, allowing you to move the jQuery library to the bottom of the document, this will work well with the nojs class in place also.
April 23rd, 2009 - 13:10
This is a good post!There is lot in use of noj’s classes,but only nojs would lead into more complications where as you can use simple claa.But since this is the advanced one which hepls up Javascript framework.
April 23rd, 2009 - 13:13
This is a good post!There is lot in use of noj’s classes,but only nojs would lead into more complications where as you can use simple a.myclass shown in the example.But since this is the advanced one which hepls up Javascript framework.But still non javascript users will find it more useful.
April 23rd, 2009 - 13:17
Actually using this it gives a descriptive to the non java script users where they can read out things,But i have some questions is that simple java .class is much simpler than this noj’s.May be let me try it out hope i will find it great.
April 24th, 2009 - 06:44
Hm, do you think a class-Attribute for the html-tag is valid? I’m not quite sure ..
April 24th, 2009 - 06:58
I like the concept, but it can get better I guess. Seems to me like a lot of these popping out all over the internet. Just read one early similar but but not jquery specific… http://performerjs.org/
This might be the new direction regarding JavaScript frameworks and cascading style sheet so it seems.
April 27th, 2009 - 00:48
i use a similar approach for IE6 hacks.
standard css file would use attribute selectors, i.e.
#content form input[type=text] {}
and i would dynamically add tags into these for IE6 so not to polute my html
$(‘#content form input[type=text’).addClass(‘ie6text’);
April 27th, 2009 - 09:58
you can do similar thing thing with YUI, only it’s little bit more simple since it has a replaceClass method:
YAHOO.util.Dom.replaceClass(‘html’, ‘nojs’, ‘js’);
April 27th, 2009 - 10:05
@Rafael
I’m thinking the non-framework dependent approach is probably the best, it will allow you to move all js to the bottom of the page before the closing body tag, other than a single script tag at the top of the template executing the following code:
<script>document.documentElement.className = ‘js’;</script>
You could than style everything you need visible ahead of time for the least visible impact to the use and the rest of the script comes in at the bottom for the best overall performance.
May 1st, 2009 - 08:44
Good write up. For only javascript version I would recommend reading this post.
May 1st, 2009 - 08:53
@Brian
Thanks for the comment, but what exactly is a jQuery enabled browser? I’ve never heard of such a thing and doesn’t make sense to me, jQuery is a javascript framework not something the browser does or does not support, if hide is a concern you should look for other ways to handle your menus such as absolute positioning the menu out of view when it’s not visible.
May 3rd, 2010 - 08:12
Genial dispatch and this post helped me alot in my college assignement. Thank you as your information.
May 4th, 2010 - 11:56
Great tip! I like the non-jQuery method, simply because, well, you don’t have to load jQuery if you don’t want to.
Also, I like the suggestion of using the tag instead of the tag as the “class” attribute appears to be technically supported only by the former and not the latter…
http://www.w3schools.com/tags/tag_html.asp
http://www.w3schools.com/tags/tag_body.asp
May 4th, 2010 - 11:58
oops, markup was filtered out of previous post. It should read…
“…I like the suggestion of using the tag instead of the tag…”
May 4th, 2010 - 11:59
heh, filtered that out too. Use “body” tag rather than “html” tag. That’s all
May 4th, 2010 - 13:15
of course, upon trying to use the “body” tag instead of the “html” tag I ran into the now obvious issue of trying to access a nonexistend DOM element.
So…. i guess you can either use a non-standard attribute on the “html” tag, or take your line of JS out of the head and slip it in immediately after the opening body tag. I’m trying the latter, with the modification to simply remove the “nojs” class (thereby preserving any other class that I might want to use in the future)
document.body.className = document.body.className.replace(/\s*nojs\s*/, “”);
May 4th, 2010 - 13:23
So everyone wants to recommend the use of the js class on the body element instead of the html element. Call me rogue and tell me my html is invalid, I haven’t found a browser yet that doesn’t recognize what I’m doing and I use this technique on the number 3 retail site in the world and it works well, with no flash of incorrectly styled content. While I would tend to agree that valid markup is the best, in this case, why jump through hoops to prevent adding the class to the html node, it’s like trying to get jQuery to run through jslint, ask yourself why you’re jumping through hoops to end up with a less than adequate solution.
May 4th, 2010 - 13:39
agreed webguy. FWIW, I don’t think document.body is standard JS, yet all modern browsers seem to support it
May 4th, 2010 - 14:59
document.documentElement.className = “js”; at the top of the head section does the trick for me. I wrote another more recent article http://greatwebguy.com/programming/css/writing-javascript-specific-css/, but everyone ends up reading this one because it has jQuery in the title. Go figure.