:hover Considered Harmful

I was on iChat with Andy Clarke recently, shooting the breeze about CSS and accomplishing this or that cross-browser effect.

He asked about applying a change of style to a <p> element when the cursor hovers over it. That sounds like a job for JavaScript and the DOM, I said. You want to dynamically update the style of an element based on the user’s actions… a classic case of DHTML.

Ah, but what if it was an <a> element? Then the simple application of CSS pseudo-class :hover would take care of dynamically altering the style.

This prompted Andy to ask why it isn’t possible to apply the :hover to other tags (cross-browser, remember… IE for windows doesn’t want to play along).

The question that popped into my mind was quite the opposite: why are we allowed use the :hover pseudo-class at all?

When I was giving my SkillSwap presentation with Richard a while back, I kept hammering home the idea of applying layers to a document. Begin with a well-marked up, semantically correct document. Then apply a presentation layer using CSS. Then apply a behaviour layer using JavaScript and the DOM.

My main point was that one shouldn’t mix up mark-up with presentation (e.g. using <font> tags, inline styles, etc.) or mix up mark-up with behaviour (e.g. inline event handlers, <script> tags in the body, etc.). But an equally valid lesson would be that one shouldn’t mix up presentation with behaviour.

Over at A List Apart, there are many articles that show how to achieve behavioural effects using nothing but CSS. But why is this considered a good thing? Isn’t that like showing how to achieve styling using nothing but HTML (“by using the <font> tag, I can eliminate the need for CSS..”) or JavaScript?

For instance, it is possible to style a document entirely with JavaScript. Once the document loads you could loop through all the <p> tags for instance, and style them in a certain way:

window.onload = function() {

var paras = document.getElementsByTagName(‘p’);

for (i=0;i<paras.length;i++) {

paras[i].style.fontSize = ‘.8em’; paras[i].style.fontFamily = ‘serif’;

}

}

But that would not only be a very long-winded way of doing it, it would be abusing the DOM to do the work of CSS:

p { font-size: .8em; font-family: serif; }

And yet, when it comes to doing things the other way around, it would appear that the CSS spec has clearly stepped on the DOM’s toes in the case of :hover. Or should I say, in the case of onmouseover.

The reason why the JavaScript example given above is silly is that there’s no behaviours involved (well, apart from the completion of the loading of the page). In the case of hovering a cursor over a page element, however, it’s a clear cut case of attaching a certain behaviour to an element when an event is fired.

window.onload = function() {

var links = document.getElementsByTagName(‘a’);

for (i=0;i<links.length;i++) {

links[i].onmouseover = function() {

this.style.backgroundColor = ‘red’;

}

}

}

That’s just the kind of thing that the DOM was born to handle (along with a corresponding onmouseout behaviour). Yet CSS comes in and offers a quicker, more seductive solution:

a:hover { background-color: red }

Presentation and behaviour… the twain have met, the waters are muddied, the issues are confused.

It’s a similar story with the :active pseudo-class. Why is that only applied to links? Why can’t I use it to add onmousedown behaviours to any element?

I do realise that :hover is extremely useful, albeit restricted in browser support. I’m mostly just surprised that it made it into the spec. Is that simply because, back when the specs were being drawn up, mouseover effects were about the only thing for which JavaScript was used? Was it a case of the theory of separation giving way to the practicalities of the day to day demands of designing web pages?

Similar justifications could be used for the re-introduction of the <font> tag or non-standard Document Object Models…. “Aw, c’mon, just this once. It’ll make life easier for the web designers, honest”.

The way that CSS has usurped the mouseover behaviour from the DOM sets a dangerous precedent. It’s a slippery slope to all-out anarchy.

Now, if you’ll excuse me, I need to extract my tongue from my cheek and do my best to ignore the sound of Edsger Dijkstra spinning in his grave as I add to the geek tradition of name-checking his seminal article.

Have you published a response to this? :

Responses

SCAREa IE6oueidan

@adactio …the :active pseudo-class. Why is that only applied to links? Why can’t I use it to add onmousedown behaviours to any element?” đź‘Ť

hexalys

@gauntface Well :active does the job if it worked cross-browser, agreed. Though you could use another pseudo that handle tap/touch toggles.

# Posted by hexalys on Wednesday, October 29th, 2014 at 9:24pm

hexalys

@gauntface :focus doesn’t give CSS toggle controls. You only have limited checkboxes for that. So, some sort of a CSS :toggle would be nice.

# Posted by hexalys on Wednesday, October 29th, 2014 at 9:28pm