• No-JavaScript CSS

    Nov 28 2005

    On one of my web sites, I use JavaScript to show/hide div layers containing each section. I have links to "#section-five" for example, but the onclick event changes the section-five div to display: block; and the previous div to display: none;. This is designed so that browsers without CSS or JavaScript will still be able to use the links as regular anchor links. This assumes, though, that the visitor would either have both CSS and JavaScript, or neither.

    Since I wrote this, I've been struggling with how to deal with visitors who have CSS but not JavaScript. Today I figured out a way to do this.

    The typical solution would be to have display: block; set by default, then to use JavaScript to set display: none; onload. I tried this solution, but I didn't like how all the layers appeared at first, then suddenly disappear. I wanted a solution that wouldn't affect the experience for most users.

    All I needed to do was display different CSS to users without JavaScript. To accomplish this, I first considered setting disabled on the style sheet, then using JavaScript to enable the CSS link. This didn't work right in Firefox because Firefox ignores the disabled attribute of link tags.

    Next, I tried setting the href on the link tag to href="", then dynamically setting the href using JavaScript. This worked good, except then users without JavaScript would be forced to see the page without CSS. It was perfectly usable but looked pretty boring.

    Finally, I came up with this compromise. The link tag on the page is:

    <link rel="stylesheet" type="text/css" media="screen"
     href="nojavascript.css" id="stylesheet"/>

    so by default, visitors will get a "nojavascript.css" CSS file. This file contains:

    @import "screen.css";
    div.section { display: block; }
    #ads { display: none; }

    So without JavaScript, the page has all the div layers displayed, except the ads. (Adsense and Chitika won't work without JavaScript anyway.) Also, by using an @import, I won't have to maintain two almost-identical CSS files.

    Next, I added a line to the JavaScript file attached to the page:

    document.getElementById('stylesheet').href = "screen.css";
    

    Note that I didn't put it in an onload function. I don't want the page to change once it's been loaded; I want it to look right from the start. If you do this, you'll have to make sure that the <script> tag comes after the <link> tag.

    The other nice thing about this method: it ensures that users with browsers that doesn't support getElementById will still get the nojavascript.css file. This is important because it is the only method I use for handling the onclicks.

    That's it. Simple, yet powerful.

  • Comments

    1. kontur at 9:59am on June 28, 2006

    nice article ;)

    2. Matthew Taylor at 1:18am on June 7, 2007

    I've been looking for a solution like this for ages, finally I've found it!

    It's a pity we can't use the noscript tags in the head of an html document, if we could, a non-JavaScript-CSS file could be linked to in this way without using JavaScript at all. That is obviously too good to be true.

    3. mike foskett at 1:35pm on November 8, 2007

    Have you considered doing this instead:

    <script type="text/javascript">/*<![CDATA[*/document.documentElement.className="hasJS"/*]]>*/</script>

    Add the script directly after the page title. Now refernce the hide div like so:

    .hasJS div.hide {display:none}

    html.hasJS only exists if JS is available.

    The real beauty is the speed of it. Because it's ran before the style sheet there is zero delay in both loading and implementation. Oh, and it's valid W3C grammar to boot.

    4. Dan Lim at 10:44am on July 26, 2010

    This is a nice solution. I'm surprised google didn't bring more results, would have thought this would be a common problem found by developers.

    Commenting is now closed. Come find me on Twitter.