Wednesday, May 20, 2009

Changing html classes - poor IE performance

How do you change the display of multiple similar elements on an html page? The simple answer is to give the elements a class, and then use a CSS rule to modify the output. This works for a static display. But what if changes are needed? Changing the CSS rule seems to be the logical answer. However, this requires going through lots of hoops - and often is not worth it.

First you need to find the stylesheet:


var getStyleSheet = function() {
var ss = document.styleSheets;
for (i=0;i<ss.length;i++) {
var s = ss[i];
if ((s.href != null) && (s.href.indexOf('myStyleSheet.css') != -1)) {
return s;
}
}
return null;
}


The you need to find the appropriate rules. The only catch: Internet Explorer does things wrong. So you have to go through a few tricks to get to the right place:


var getCssRules = function () {
if (g.cssRules != null) {
return g.cssRules;
}
var s = getStyleSheet();
if (s.rules) {
s = s.rules;
}
else {
s = s.cssRules;
}
g.cssRules = s;
return g.cssRules;
}


Once you find the appropriate rule, you need to set the appropriate value. Again, syntax is different:


var changeStyle = function(selector,key,val) {

for (i=0;i<rules.length;i++) {
if (rules[i].selectorText == selector) {
if (rules[0].style.setProperty) {
rules[i].style.setProperty(key,val,null);
}
else {
// IE
rules[i].style[key] = val;
}
return;
}
}
}


All seems well and good. It works for IE, Safari and Firefox. In Safari, it runs at lightning speed. In Firefox, it is fast. But IE? Well, IE takes its time. If it is setting the rule to the same value, then it is zippy. However, setting to a new value can take nearly forever (from times in milliseconds to seconds).

The alternative is to simply find all the elements in the document and manually change them. I use Robert Nyman's getelementsbyclassname, though many other js libraries have similar functions (and the newest firefox has it natively, but that doesn't help much for IE issues.)
This method seems to slow down Safari in updates (but somewhat speed it up in creating new rules.) However, it does significantly speed up IE, and make it almost competitive with other browsers. Since elements and a container can be specified it is also easier to narrow it down to a specific section of the document, thereby improving performance.


var changeStyle = function(selector,val) {
selector = selector.substring(1);
var elements = getElementsByClassName(selector,'tr',document.getElementById('containerelement'));
for (el in elements) {
elements[el].style.display=val;
}
}

No comments:

Post a Comment