Reliably attaching CSS
In response to PPK’s 24 ways article I thought I should describe the method I currently choose employ to hide elements onload. I have gone through this briefly in my article ‘releasing the permalink slideshow‘. As PPK mentioned, it is important to hide elements not needed for browsers that don’t support JavaScript. The most important part of this hide technique is that there is no flicker in the period that the page is being loaded.
PPK suggests using document.write as to insert style elements inside the head. I propose instead using JavaScript’s try / catch functionality to attach a stylesheet. Elements that need to be in the source for accessibility purposes, or need to be displayed for browsers without JavaScript, can then have a class that will hide them for browsers with JavaScript.
I like to use the try catch to ensure there are no issues in appending the link element to the head. The link contains the stylesheet that will then hide the elements that need to be hidden:
function setCSS(css) {
try {
// append stylesheet to alter
document.getElementsByTagName("head")[0].appendChild(css);
} catch (e) {
setTimeout(function(){setCSS(css)}, 100);
}
}
// create CSS element to set up the page
var css = document.createElement(”link”);
css.setAttribute(”href”,path/to/stylesheet);
css.setAttribute(”rel”,”stylesheet”);
css.setAttribute(”type”,”text/css”);
// attempt to add the css and then keep trying till we do
setCSS(css);
css = null;
The setTimeout ensures that if there is an issue attaching the link to the bottom of the head (e.g. if the head hasn’t finished loading when the link is trying to be attached) it retries after 100ms. Resetting the css variable to null avoids potential memory leaks.
Is this really worth the setTimeout overhead? What’s wrong with ppk’s solution?
James Wheare - December 6th, 2006 at 7:59 pmFWIW, I’ve recently started using Ian Hickson’s XHTML-friendly replacement for
document.write- which seems much cleaner and less error-prone than thetry ... catch ... setTimeoutapproach:DOM.injectNode : function(_node) {
var t = document.getElementsByTagName(’*');
var p = t[t.length-1].parentNode;
p.appendChild(_node);
};
(Via Sam Ruby)
Már - December 7th, 2006 at 1:34 amI don’t believe that this try catch method is in direct conflict with PPk’s method. He talks in quite a general sense about the importance of using such a method to avoid the flicker of content that should not be shown to browsers with javascript, I thoroughly agree with this.
The solution detailed in the entry above is an alternative to using document.write to insert styles in the head. I don’t like to use styles in the head especially for big projects where the same elements may need to be hidden across multiple pages. In addition to this, sometimes it is not just hiding elements that you need to do. It could be that much more complicated styling is needed for javascript enabled browsers, using an external stylesheet makes sense from performance and also consistency purposes.
The catch is hardly ever used, it is really only there to make sure that the head loaded ok before you try to append a stylesheet to it, if for some bizarre reason the head does fail to load it will wait and try again. I believe this is worth any overhead because it is that bit cleaner for using document.write or putting an empty link element in the head. Like most things though, it comes down to a question of purpose and taste.
natbat - December 7th, 2006 at 4:04 pm“Is this really worth the setTimeout overhead?”
Since we are not dealing with several hundred separate Timeout’s, and heads of documents are -very- quick to load, there should be no noticable performance problems, including the slowest of computers. I guess even the computer itself should have hard time noticing it!
Emrah Baskaya - January 21st, 2007 at 10:07 am