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:
-
document.observe("dom:loaded", function() {
-
// initially hide the reveal container
-
$('revealContent').hide();
-
});
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.
-
#revealContent.show {
-
display: block;
-
}
// 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><head></code> before it finished loading, but fortunately this isn’t the case.</p>
<p>You could also include a stylesheet or a <code><style></code> tag in a <code><noscript></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>
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 Robbins — March 4th, 2009 at 6:50 pm
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.
admin — March 4th, 2009 at 7:01 pm