Internet Explorer frustrates the living hell out of me. Event though IE 7 is finally out, it doesn’t mean that IE 6 can be ignored. I really look forward to the day when my CSS files aren’t full of unnecessary classes and hacks because the major browser vendors got it right and because everyone has casted away the garbage. Until then, I am still in search of tricks to simplifying my life.
One of these tricks is to make IE pretend like it knows how to use the :hover pseudo-class on all tags.
If you have ever tried to do a suckerfish dropdown, then you have gone through the same thing: excitement as you have learned how to use structural markup to create a dropdown and then frustration as your work has been nullified by IE. The fix involves creating duplicate selectors of those using :hover, but instead of using :hover, replace it with a class name .hover. Making what are essentially duplicates and managing more content doesn’t sit well with me. The other trick to getting suckerfish to work in IE is to use JavaScript. The script will add a class definition to the tag when a user’s mouse if over the element and then removes the class when the users mouse is no longer over it. Since this method uses JavaScript to solve one problem, why not make it solve both?
The Code
There is a requirement to using this code and that is you will need prototype 1.5.
var HoverBehavior = Class.create();
HoverBehavior.prototype = {
initialize: function() {
$A(document.styleSheets).each( function(stylesheet) {
$A(stylesheet.rules).each( function(rule) {
if( rule.selectorText.match(/:hover/i) ) {
stylesheet.addRule( rule.selectorText.replace(/:hover/ig, '.hover'), rule.style.cssText );
}
});
});
$A(arguments).each( function(arg) {
$$(arg).each( function(tag) {
Event.observe(tag, 'mouseover', function() { Element.addClassName(tag, 'hover'); });
Event.observe(tag, 'mouseout', function() { Element.removeClassName(tag, 'hover'); });
});
});
}
};
In summary, it loops through all of the stylesheets, and for each stylesheet, it loops through all of the rules. The first part of the initialization will only work in IE. When looping through the rules, IE uses the rules attribute while others use cssRules. Since this is only meant for IE, I am not going to bother making it cross-browser.
While looping through all of the rules, it is checking the selector text to see if :hover is in that text. If so it will append a new CSS rule to the stylesheet. The selector text for that rule is just like text of the matched selector; however, all instances of :hover have been replaced with .hover. The new rule’s style is simply a copy of the matched selector.
That covers part 1 of the suckerfish fix, part 2 is to add the mouseover, mouseout states to the tags using :hover.
Usage
After the page has been loaded, then it is time to create a new instance of the HoverBehavior class. Since this is only for IE, it would be wise to use IE conditionals as that your other users, who are using complaint browsers, shouldn’t have to process any unnecessary code.
The constructor can take any number of arguments that you would give to prototype’s @$$@ function, which are like CSS selectors themselves. I could have also done something like:
* new HoverBehavior('#nav li', '#footer li');
* new HoverBehavior('li', 'p', 'span');
* new HoverBehavior('*');
The reason I don’t assume the last one in that list is because I don’t want to kill the user’s browser. Instead of being lazy and choosing all of the elements, I only want to put the mouseover, mouseout functionality on the elements that need it.
December 14th, 2006 at 11:40 pm #Tom-Eric Gerritsen
You’re kind of reinventing the wheel! We already have fixes for this in the form of IE7 (the javascript library, not the browser) and whatever:hover.
December 15th, 2006 at 4:45 am #Adam
I have used the IE7 scripts, and I have had more problems than success using it. So I decided to break apart that I needed.
As for whatever:hover, I did not know about that.
December 15th, 2006 at 7:28 am #JTMS
@Adam - Agreed: the IE7 compatibility scripts have caused some very strange rendering issues in otherwise valid and xhtml/css. Height of block elements in some situations becomes artificially large. IE7 compatibility is a great idea, but in my opinion not yet ready for use on anything more than a personal site for testing purposes.
December 17th, 2006 at 2:14 am #Chris
You can get HTC files that do this automatically, simple declare in your css a behaviour that loads a hover.htc file [you can google this quite easily] which will give IE6 its missing functionality!!
February 19th, 2007 at 2:46 pm #Remy
HTC only works in IE.
I’ve done the same thing with Prototype, Behaviour and Event-Selectors, just as a comparison on my blog:
http://remy.supertext.ch/?p=13
Maybe it helps someone.
April 20th, 2007 at 10:54 am #e
to bad im a jquery guy…….I NEED THIS but i dont want to use prototype too….
eh o well.
April 22nd, 2007 at 9:05 am #K. Adam Christensen
well, this should be pretty easy to make it into something jQuery would like.
function HoverBehavior() {
$.each(document.styleSheets, function(i, stylesheet) {
$.each(stylesheet.rules, function(j, rule) {
if( rule.selectorText.match(/:hover/i) ) {
stylesheet.addRule( rule.selectorText.replace(/:hover/ig, ‘.hover’), rule.style.cssText );
}
});
});
$.each(arguments, function(i, arg) {
$(arg).each( function(j) {
$(this).hover(function() {
$(this).addClass(”hover”);
},function() {
$(this).removeClass(”hover”);
});
});
});
}
That’s just a quick stab at it. My first time using jQuery, although I did not test it so I don’t know if it works.
May 9th, 2007 at 7:50 am #Andrew Ryzhokhin
Hello!
This is cool script!
Good work!
Thank you!
I use this in my project!
–
Be Lucky
http://www.ardas.dp.ua
February 20th, 2008 at 8:55 am #Livingston Samuel
I’ve made a simple solution to make the hover function for non-anchor elements in IE6
Hover for non-anchor elements in IE6