Script to add CSS only when JavaScript is available

By Luke Smith on October 29, 2008 7:07 AM

If your site uses JavaScript to hide and show content, styled using display: none and (commonly) display: block, you may have an accessibility problem on your hands. The hidden content can't be viewed by users that have JavaScript turned off unless you've provided adequate navigable hooks to get to it via default html behavior (e.g. <a href="...">).

One way of addressing this is to add a class to the elements you want to hide once the DOM is in a modifiable state, but this can cause the hidden content to appear for some unknown amount of time, then disappear. Less than elegant.

Another approach might be to have a class that hides elements only when relative to a trigger class that is applied to a containing element, such as <body>, ala

<head>
    <style type="text/css">
        .js_on .hide { display: none !important; }
        ... and so on
    </style>
</head>
<body>
    <script type="text/javascript">
        document.body.className = "js_on";
    </script>
    ...
    <div class="hide">This is only hidden when JavaScript is on.</div>

That would prevent the content flicker, but if the body class is modified by another script on the page, your content could suddenly appear.

There are numerous other ways to address the problem, such as using JavaScript in the <head> to add a <link> element pointing to a stylesheet with your hide rules. Etc etc. Many ways to skin this cat.

Last night as I was falling asleep, I concocted this little script that I named script2style.js to address the problem a different way:

(function () {

var d = document,
    scripts = d.getElementsByTagName('script'),
    me      = scripts[scripts.length - 1],
    content = me.innerHTML,
    style   = d.createElement('style');

style.type = 'text/css';

if (style.styleSheet) {
    style.styleSheet.cssText = content;
} else {
    style.appendChild(d.createTextNode(content));
}

me.parentNode.replaceChild(style,me);

})();

Drop that in the <head> like so:

<head>
    ...
    <script src="script2style.js">
        .hide { display: none !important; }
        #other .selectors { ... }
        ...
    </script>
</head>

The script replaces itself with a <style> element with the same content, and since scripts are blocking, the CSS will be in place as the browser loads the remainder of the page.

To be honest, I suspect it's been done before, but it was a fun little exercise.

Here's a demo.

And here's the minified script (255b).

Update

This morning, I added support for pulling @import rules out into separate <link> elements, just for kicks.

Here's a demo for that.

And here's the minified (504b) and uncompressed (966b) script.

Your comment?

HTML is ok

No TrackBacks (http://lucassmith.name/mt/mt-tb.cgi/113)

ls.n

LucasSmith.name

Luke and Liam

I'm Luke. I am a front end engineer at Yahoo! on the YUI team.

Mostly I write about code stuff, but occassionally I'll mix in some real life. You've been warned.

Archives

Tags

Feeds

Subscribe to feed Recent entries

Content licensed under Creative Commons

Code licensed under BSD license

©2005 - 2010 Lucas Smith

Powered by Movable Type