Anne van Kesteren

CSS selectors and the DOM

Although some people noticed it directly (reading source code is so much more fun) Mark was joking. Of course it is nonsense to replace a:hover (or p:hover or whatever) with a.hover and over 10 lines of javascript. Although you can argue that you need to separate behavior from style you can also say that CSS selectors are a bit different from “just CSS” as they have nothing to do with styling. They are merely there for selecting elements. The moment CSS will get an onclick property as was once proposed (thanks Daniel) it might be the right time to have a discussion about this.

Besides Mark and myself, Faruk also made this point in his post on separating style and behaviour. His post contains far more details than mine and is certainly worth a read.

Apparently there are more people than Peter-Paul Koch and Jeremy Keith convinced of the evilness of :hover. I truly wonder why all those people write this. Why is creating a dropdown using CSS evil? Is lighting up the links in a paragraph that is hovered using CSS evil?

Comments

  1. Well, I can only answer why I write it. :-)

    Faruk and I have had discussions about this, both on- and off my blog, and the middle-ground we've reached is that CSS pseudo-classes used in the dynamic sense (for instance, a:hover to change the color of a link) is totally ok, but adding more complex behavior than that isn't a good thing to do in the CSS.

    Not because it is necessary evil, but since I personally think it really qualifies as behavior.

    I think Faruk's comment sums it up very well:

    don't abuse the :hover pseudo-class to create behavioural changes in your pages, such as displaying a submenu when you hover over the main menu link. This is behaviour, and belongs in the behaviour layer (javascript). Merely styling the link differently, however, is not a behaviour, it is style.

    My biggest fear is that many developers will add more and more interactivity through the CSS, and if that were to gain followers, the onclick event doesn't seem too far away.

    So basically, what I wanted to do was to bring up the discussion before that happens.

    Posted by Robert Nyman at

  2. It's not that it's evil, but as I think it was Jeremy who put it: the DOM has better cross-browser support than CSS. Why wouldn't you use a technique that is more universal? Plus, if you start mixing behavioural techniques across both CSS and JS then you increase the level of effort to troubleshoot. Keeping functionality separated eases development.

    It's the same reason you shouldn't do this <body style="...">. Sure you can. And it's perfectly within web standards. But it increases maintenance and increases the level of effort to troubleshoot, so why would you?

    Posted by Jonathan Snook at

  3. function createElement(element){
     if (typeof document.createElementNS != 'undefined') {
      return document.createElementNS('http://www.w3.org/1999/xhtml', element);
     }
     if (typeof document.createElement != 'undefined') {
      return document.createElement(element);
     }
     return false;
    }
    var l=createElement("link");
    l.setAttribute("rel", "stylesheet");
    l.setAttribute("type", "text/css");
    l.setAttribute("href", "data:text/css,a:hover{text-decoration:none;font-weight:bold;}");
    l.setAttribute("media", "all");
    document.getElementsByTagName("head")[0].appendChild(l);

    Posted by Mathias Bynens at

  4. From a more pragmatic point of view, a dropdown menu is often a part of a particular design/presentation (although the same can be said about a expanding/collapsing menu). For example would the build-in styleswitchers in browsers become useless since you're stuck with the same dropdown menu, targeted at the most advanced design, on designs supposed to be simpler for, lets say, an easier user experience. Maybe a dropdown menu should be consistent on every design, like a form validator or something...

    I'm not sure if I'm saying anything sensible here, but it ocurred to me that dropdown menu can be analysed as both presentational and behavioral... It might screw your design if you're required to present a useful fallback for people without javascript (horizontal menu with vertical dropdowns?).

    But this is of course strictly pragmatic... In principle I would agree that a dropdown is behavioral, but highlighting a link isn't.

    Posted by Joel at

  5. A select (dropdown) is accessible with a keyboard. Anything that "drops down" using :hover is only accessible with a mouse. This is a more important consideration than the behavioral vs presentational argument.

    Posted by Dean Edwards at

  6. don't abuse the :hover pseudo-class to create behavioural changes in your pages, such as displaying a submenu when you hover over the main menu link. This is behaviour, and belongs in the behaviour layer (javascript).

    We are styling document/element states. When you hover over an element, its state is changed and you can style that element based on that state. Controlling a child elements display based on its parent elements state, is not the same as reacting to dynamic changes in the document. What about visited links? If you've already visited a URL, any link to that URL will have that state, regardless of whether you clicked on it from that particular page. The state is set the same way as the hover state.

    Merely styling the link differently, however, is not a behaviour, it is style.

    What if we don't change the visibility of a child element and instead style the element from a 1px by 1px box to 100px by 100px box?

    Posted by hemebond at

  7. One might think your uberl33t c0der skizzles would somehow enable you to reasonably present a page in IE5/Mac. Sadly, it seems that you either lack concern for widespread presentation or you simply don't know how - in both cases going against what you preach down to people with.

    If you were really smart, you would have already showed Matt how to fix the pre issue. Wait, maybe he thinks you suck, too. I, too, find it difficult to take you seriously after seeing this site.

    Go ahead and nuke this comment, Annie. You cannot under any circumstances allow anyone to critique your work - only you are allowed to do that to others, right?

    LMAO

    Posted by laughingboy at

  8. laughingboy, yeah I’m really stupid. I don’t own a Mac, neither do I care for a bit about IE5 on the Mac. About the PRE element, it will be supported eventually. But don’t think Matt can use my solution as I’m using an older WordPress version and not CVS.

    Now can we get back on topic? You can contact me by e-mail for other flames.

    Posted by Anne at

  9. Dean, good point. Although I think you could make that work too using :focus along with it, not?

    Posted by Anne at

  10. Dean > Isn't that why people are supposed to provide every single link as functional (including the top level elements, which can link to an empty page with a serie of lower level links) when creating dropdown menus?

    So that the pages themselves stay accessible for the CSSly crippled?

    Posted by Masklinn at

  11. hemebond, then you present the box differently? You can look at it from both ways.

    Posted by Anne at

  12. Anne, :focus might work and would be interesting to see in action. Anyone want to recreate Eric Meyer’s Pure CSS Menus using :focus?

    Posted by Dean Edwards at

  13. You could probably do it, but you would need to tell the browser to allow the element to be focusable...

    Posted by The Wolf at

  14. Here is my demonstration of using the focus psuedo-class to make dropdown menu, sadly it doesn't appear to work with the accesskey attribute and requires browsers that allow you to specify an element as focusable, like I have with the Mozilla specific -moz-user-focus CSS property.

    Its not an evil thing to use this Mozilla specific CSS property because its something that will probably be part of the CSS3 standard.

    Posted by The Wolf at

  15. The Wolf, I can’t tab through it. Note by the way that CSS3 probably won’t define such a property. I expect the WHATWG to provide ways to make elements focusable.

    Posted by Anne at

  16. Anne, I don't know what could be done in current browsers to make it more usable, but the basic idea works and I'm sure we will find a way of doing it.

    Heck, perhaps we can use Marks example instead of using CSS :)

    Posted by The Wolf at

  17. Forgot to say: Target based menu systems will alow the user to tab through and use the accesskey attribute.

    Posted by The Wolf at

  18. Dean > from a 5 minutes experiment with Web Dev toobar on Eric Meyer's menu, it looks like only the link (a) is focused (not the "li" it's in), which means that you'd have to climb to the parent level of the focused link to apply the menu display style.

    I'm not certain of that, but it sure looks like this

    Posted by Masklinn at

  19. In it's essence, using :hover to show a submenu is styling based on state. It is true, though, that this is a very behaviour-like situation. I'm not really sure where to draw the line here, but since I'll need JavaScript to get this working in IE I'll be just as likely to create a nice menu script.

    Posted by Mark Wubben at

  20. Mark, I've got a challenge for you! Try to make some JavaScript that emulates the behavior of the :target psuedo-class in IE.

    No, I'm not trying to be rude, this would honestly be something very cool, and to be honest (still), my JavaScript skills are not that good.

    Posted by The Wolf at

  21. That should be possible... challenge accepted!

    Posted by Mark Wubben at

  22. Great to hear it! If you can do it, everyone owes you a beer or something... :)

    Posted by The Wolf at

  23. Here we go! Now, where's the beer?

    Posted by Mark Wubben at

  24. Mark, you've been lazy on that one, masterfully hacking for 30 minutes and using li.target when li.target, li:target would've made it cross browser (no other change required) is quite ?sad? (not sad in fact, but I don't know what to use instead. Lazy, maybe?).

    Thank you anyway, page's been bookmarked and I'm among the ones who owe you a beer... Here you are.

    Posted by Masklinn at

  25. Masklinn, mmm that beer looks nice! If I ever add support for ":target" to IE7 do I get one too?

    Posted by Dean Edwards at

  26. No way, you won't get any beer from me before you release IE7 1.0 stable.

    Because I'm waiting for it, and you made me.

    Meanie

    Posted by Masklinn at

  27. Masklinn, well, it's an implementation for IE, couldn't let it work in Mozilla then, could I? As for that beer, it looks oddly similar to those coffee mugs we have in the house. You sure it's Guinness? ;-)

    Posted by Mark Wubben at

  28. Well, I can understand about the "IE implementation", but I still felt sad not being able to see the page within my faithful Firefox (granted it was useless to do so, but I still got to tweak my CSS to activate target). It wasn't about letting it work with Moz or not, but more like... about showing how the existing standard feature could be made IE-compatible?
    Stupid justification of the day: by not implementing :target, you were browser-elitist, you... beer drinker.

    Beer wise, yes I'm sure it's guiness since it was drunk by a very friend of mine, it's probably dark because of the badly lit room and cam flash. Anyway, it IS guiness, and very much drinkeable

    My coffees are so dark they don't even reflect light anyway, so it couldn't be one.

    Posted by Masklinn at

  29. The Wolf, I can’t tab through it. Note by the way that CSS3 probably won’t define such a property. I expect the WHATWG to provide ways to make elements focusable.

    Like here?

    When an element that does not normally take focus has the tabindex attribute specified with a positive value, then it is added to the tab order and is made focusable. When focused, the element matches the CSS :focus pseudo-class and key events are dispatched on that element when appropriate, just like focusing a link.

    I've played around with :focus, but I don't see any way to let the nested ul to remain visible while the child li's a-elements are focused...

    It would have been simple with a parent selector: ul < li < a:focus, but I think implementors disliked it.

    Posted by Joel at