View Full Version : IE7 CSS update problem when changing attributes and using selector-based rules

10-27-2006, 05:33 PM
I have some code that relies upon the manipulation of element attributes. A very simple example is to use mousedown to set a "state" attribute to "down", and then mouseup to set it back to "default". The CSS rules would then use [state=down] to make specific differences for the down state.

Probably best if I produce some example code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<style type="text/css">
.thing {
cursor: default;
background-color: #eeeeee;
border: 2px solid #000000;
height: 20px;
width: 150px;
padding: 2px 8px;
display: block;
position: relative;
.thing[state=down] {
background-color: #bbbbcc;

<div id="thing" class="thing">Click me!</div>
<div class="thing" state="down">Don't click me.</div>
<script type="text/javascript">
var thing = document.getElementById("thing");
thing.onmousedown = function() {
if (thing.setAttribute) thing.setAttribute("state", "down");
else thing.state = "down";
thing.onmouseup = function() {
if (thing.setAttribute) thing.setAttribute("state", "default");
else thing.state = "default";

The code above is a very simplified version of what's happening in my code. We're only bothered with one element here, so I've hard-coded a reference to that element being clicked, in order to keep everything to a minimum, rather than handle the event in a more sophisticated way.

The code works fine in Firefox, and the div's background colour changes.

However, in IE7, nothing happens.

I included a second element with the state attribute pre-set to "down", to show that IE7 is indeed properly applying the rules. It just doesn't seem to be doing so when I change the attribute dynamically.

A point of interest - if I attach the behaviour to the mouseover and mouseout events, the same thing happens (i.e. nothing!). However, if I include a rule anywhere that uses :hover - even if no elements exist to match the rule - then it will suddenly work. To see what I mean, change "onmousedown" to "onmouseover", and "onmouseup" to "onmouseout" in the JavaScript code above - no behavioural change. Then add a CSS rule - ".something:hover {}" - and suddenly it works.

This has led me to believe that IE7 has some code somewhere under the hood that only recalculates styles on mouseover/mouseout if one or more :hover selectors are used. Bizarre, but that's Microsoft!

The question therefore seems to be, how can I force IE7 to recalculate the CSS being applied? I don't really mind if I have to call some function every time I change an attribute - although it would be a bit of a pain, I just want this stuff to work. I've been Googling about this for over a week, on and off, and not found anything. I've also not come up with any fixes or alternatives.

Otherwise, if I'm doing something wrong, please could someone point it out! :)

[EDIT:] I just want to point out that I'm aware I could add/remove a class to the element's class/className attribute to achieve the effect that way. It's just that using attribute selectors is less messy, and more semantic.

10-28-2006, 02:09 AM
Okay, for anyone who's interested (and for anyone else who runs into this problem in the future!) I'm found the solution.

All that is required is:

if (thing.className) thing.className = thing.className;

By setting the class to, uhhh, exactly the same value (yeah, I know it seems silly!), IE updates the applied styles. So, this can be called after each change that will require an update.

I went one further and put "this.className = this.className" in a function called "refresh", which I attached to every element using an HTC behaviour. Additionally, since I already use a modified setAttribute function, I put a call to the new refresh function in there. I'm sure it's not the most efficient thing ever, as it's bound to introduce some uncessary recalculation, but it works - and works well. On a scale of ugly to elegant, I'd rank this fix as fairly elegant ;)

Damn Microsoft and their weird ways... how many more hours am I destined to spend debugging in IE and searching for obscure information! :(