4umi.com/web/css/hover

whatever:hover

Useful JScript

This page serves as an example of the use of the :hover pseudo-selector in css. It is supported natively by W3C standards-compliant browsers for all types of elements, but only for <a> anchors in Internet Explorer. Peter Nederlof has written a script in an .htc file, a so-called HTML Component to add behaviour which is ignored by all browsers except ie, to allow to use of the :hover pseudo-selector on arbitrary elements.

Implementing the script

The script file is included in the document by specifying the following rule in a stylesheet:

body { behavior:url( hover.htc ); }

The behavior property will invalidate the CSS, but from a pratical point of view validation does not make nor break a page. The filename in the brackets may be wrapped in single or double quotes, and it may be an absolute or relative url. When all is well, :hover rules will then work not only in up-to-standards browsers but also in IE:

body{ background: #fff; } 
body:hover { background: #eee; }

Various selectors

legend:hover { background: lime; }

fieldset:hover { background: green; }

h3:hover { font-style:italic; text-decoration:underline; }

Download

The selectors html:hover and *:hover for arbitrary elements are not properly working. Both have been removed, the results are not relevant anyway.

The script

The behaviour is attached in onmouseover and onmouseout events at the time the documentreadystate reaches complete. Any elements created after that moment will be unaffected. This is why the colored <span> elements below, which are created some miliseconds after page load, do not light up the same way as the other spans on the page do.

var currentSheet, d = window.document, activators = {
  onhover: { on: 'onmouseover', off: 'onmouseout' },
  onactive: { on: 'onmousedown', off: 'onmouseup' }
};
function parseStylesheets() {
  var s = d.styleSheets, i = s.length;
  while(i--) {
    parseStylesheet( s[i] );
  }
}
function parseStylesheet( sheet ) {
  if( sheet.imports ) {
    var rules = (currentSheet=sheet).rules, imports = sheet.imports, i = imports.length;
    while(i--) {
      parseStylesheet( imports[i] );
    }
    i = rules.length;
    while(i--) {
      parseCSSRule( rules[i] );
    }
  }
}
function parseCSSRule( rule ) {
  var select=rule.selectorText, style=rule.style.cssText;
  if( !( /(^|\s)(([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active)/i ).test(select) || !style ) { return; }
  var pseudo = select.replace( /[^:]+:([a-z-]+).*/i, 'on$1' ),
   newSelect = select.replace( /(\.([a-z0-9_-]+):[a-z]+)|(:[a-z]+)/gi, '.$2'+pseudo ),
   className = ( /\.([a-z0-9_-]*on(hover|active))/i ).exec(newSelect)[1],
   elements = getElementsBySelect( select.replace( /:hover.*$/, '' ) ), i = elements.length;
  currentSheet.addRule( newSelect, style );
  while(i--) {
    new HoverElement( elements[i], className, activators[pseudo] );
  }
}
function HoverElement( node, className, events ) {
  if( !node.hovers ) { node.hovers={}; }
  if( node.hovers[className] ) { return; }
  node.hovers[className] = true;
  node.attachEvent( events.on, function() { node.className += ' ' + className; } );
  node.attachEvent( events.off, function() { node.className =
    node.className.replace( new RegExp( '\\s+' + className, 'g' ), '' ); } );
}
function getElementsBySelect( rule ) {
  var b = rule.split( / / ), i=b.length, nodes=[d];
  while(i--) {
    nodes = getSelectedNodes( b[i], nodes );
  }
  return nodes;
}
function getSelectedNodes( select, elements ) {
  var i, j, result, node, nodes = [],
   classname = ( /\.([a-z0-9_-]+)/i ).exec( select ),
   identify = ( /\#([a-z0-9_-]+)/i ).exec( select ),
   tagName = ( /^[a-z0-9]+/i ).exec( select.toUpperCase() ) || '*';
  for( i=0; i<elements.length; i++ ) {
    result = elements[i].getElementsByTagName(tagName);
    for( j=0; j<result.length; j++ ) {
      node = result[j];
      if( ( identify && node.id !== identify[1] ) || ( classname && !( new RegExp( '\\b' + classname[1] + '\\b' ).exec( node.className ) ) ) ) {
        continue;
      }
      nodes[nodes.length]=node;
    }
  }
  return nodes;
}