Adding CSS rules with JavaScript to hide content on page load

Update: I’ve had to update the code to get it to work reliably in Safari 2. Much thanks to this article on the YUI Blog for another solution.

A lot of ajax-y web pages involve hiding and showing content. My current project has a tons of content related to a video in dynamic reveals that the user can open and close. Of course, accessibility is important, so for users without JavaScript enabled, all of this hidden content should be visible.

Typically, JavaScript would explicitly hide this content as soon as it is available. Something like:

// using prototype.js
  1. document.observe("dom:loaded", function() {
  2.   // initially hide the reveal container
  3.   $('revealContent').hide();
  4. });

I chose prototype.js because of its notorious file size, and I know a lot of you still don’t compress and gzip their JavaScript! If you’re loading a lot of JavaScript, HTML, and CSS, chances are pretty likely that the #revealContent element will display before that that function has a chance to run.

So how do we hide that element before it has a chance to load? The technique I’m using adds a CSS rule to a new stylesheet as soon as possible, i.e. when the JavaScript is interpreted.

/* Add a rule in CSS that lets you override the generated rule */
  1. #revealContent.show {
  2.     display: block;
  3. }
// JavaScript

var CSSRules = function() {

	var headElement = document.getElementsByTagName("head")[0],
		styleElement = document.createElement(”style”);
	styleElement.type = “text/css”;
	headElement.appendChild(styleElement);

	// memoize the browser-dependent add function
	var add = function() {
		// IE doesn’t allow you to append text nodes to
 elements
		if (styleElement.styleSheet) {
			return function(selector, rule) {
				if (styleElement.styleSheet.cssText == ”) {
					styleElement.styleSheet.cssText = ”;
				}
				styleElement.styleSheet.cssText += selector + ” { ” + rule + ” }”;
			}
		} else {
			return function(selector, rule) {
				styleElement.appendChild(document.createTextNode(selector + ” { ” + rule + ” }”));
			}
		}
	}();

	return {
		add : add
	}
}();

CSSRules.add(’#revealContent’, ‘display: none !important’);

// later
$(’revealContent’).addClass(’show’);
</pre>
<p>I haven’t tested this exhaustively, but it works as intended in Internet Explorer 6 and 7, Firefox 2 and 3, Safari 2 and 3, and Opera 9. I originally expected some strange behavior from adding elements to the <code>&lt;head&gt;</code> before it finished loading, but fortunately this isn’t the case.</p>
<p>You could also include a stylesheet or a <code>&lt;style&gt;</code> tag in a <code>&lt;noscript&gt;</code> tag, but I prefer to keep all of this behavior in JavaScript.</p>
<p><strong>Update:</strong> The old code:</p>
<pre lang=”javascript”>
// JavaScript
var CSSRules = function() {

    // create a stylesheet
    var stylesheet = document.createElement(”style”);
    stylesheet.setAttribute(”type”, “text/css”);
    document.getElementsByTagName(”head”)[0].appendChild(stylesheet);
    stylesheet = document.styleSheets[document.styleSheets.length - 1];

    return {
        add: function(selector, rule) {
            // the Microsoft method
            if (stylesheet.addRule) {
                stylesheet.addRule(selector, rule, 0);

            // the standard method
            } else if (stylesheet.insertRule) {
                // safari 2 apparently ignores this
                stylesheet.insertRule(selector.concat(’{’ + rule + ‘}’), 0);
            }
        }
    };
}();

CSSRules.add(’#revealContent’, ‘display: none !important’);

// later
$(’revealContent’).addClass(’show’);
</pre>

« Developing Silverlight 1.0 RIAs: XAML Developing Silverlight 1.0 RIAs: JavaScript Optimization »

2 Responses to “Adding CSS rules with JavaScript to hide content on page load”

  1. I can’t get this to work with mac firefox. Perhaps I am doing something wrong, but once I have set the display to none with this code, I lose the ability to toggle display with js /css. It just always stays display:none! Any ideas?

    Christopher RobbinsMarch 4th, 2009 at 6:50 pm

  2. Can’t make too many guesses without seeing you code, but if you’re overriding the “display:none” with another CSS class, maybe the specificity of your css selector isn’t enough.

    adminMarch 4th, 2009 at 7:01 pm