Best css-selectors questions in March 2012

Two CSS Classes: Which one Wins?

11 votes

The markup below aligns SAMPLE TEXT to the left.

To me, it seems like it should be aligned to the right. The class that aligns to the right is declared after the one that aligns left. And the class that aligns to the right is even referenced last. So why does the class that aligns to the left win?

CSS

.table {
    width: 100%;
}
.table td {
    text-align: left;
}
.cell {
    text-align: right;
}

HTML

<table class="table">
    <tr>
        <td class="cell">
             SAMPLE TEXT
        </td>
    </tr>
</table>​

Please see my jsFiddle Example.

The .table td selector has a higher specificity. CSS specificity rules are kind of weird... IDs weigh more than class names, which weigh more than tag names.

The specificity rules, in a nutshell:

  • For each tag name, add 1.
  • For each class name, add 10.
  • For each ID, add 100.

The higher values will always override the lower ones. In the case of a tie, the last rule loaded wins.

Is `:not(:hover)` and `:hover` a safe way to hide accessible elements?

11 votes

Sometimes it appears helpful to make certain page elements only visible on e.g. hovers. An example is stackoverflow's "feedback - Was this post useful to you?"-widget. As those elements might be crucial to the interface, such a show-on-hover-feature should be a progressive enhancement or, in other terms, unobtrusive and degrade gracefully.

The usual way appears to be employing javascript, e.g. hiding the elements and making them available when a parent element is hovered. The reason for that choice might be :hover is not support for all elements especially in legacy browsers, thereby forbidding you to hide elements in the first place up to css2. (for a js/jQuery example cf. jquery showing elements on hover)

I wonder if you can achieve such a feature safely* with pure css3, using :not(:hover) and :hover, not affecting older browsers. As far as I can see, the requirement is that every browser supporting :not() must support :hover for all elements. According to the following sources, that appears to be the case

Example implementation: http://jsfiddle.net/LGQMJ/

What do you think? Any objections or other sources?

*by safely I mean the browser should always show all elements as a last resort.

Your solution looks alright for CSS3. There isn't anything I can think of to improve your solution for modern browsers as the opacity property will never be applied by browsers that don't support it anyway.

There is literally no other browser besides IE6 and NN4 (and older) without support for :hover on elements other than a. As implied in your question, all browsers that support :not() are known to also fully support :hover.

That said, you end up leaving IE7 and IE8 missing out on the hover effect, the latter of which is still quite prevalent. You're probably looking to support IE6 as well, but here's a solution that I believe will address these concerns, if you need it:

  1. Omit :not(:hover) altogether so your first selector becomes less specific rather than equally specific to your second selector with :hover, and you can reach out to IE7 and IE8 which don't support :not() but do support :hover on all visual elements:

    div span.question {
        opacity: 0;
    }
    div:hover span.question {
        opacity: 1;
    }
    
  2. Use the visibility property instead of the opacity property to reach out to IE7 and IE8 which don't support CSS3 opacity:

    div span.question {
        visibility: hidden;
    }
    div:hover span.question {
        visibility: visible;
    }
    
  3. Use CSS2/3 combinators that IE6 doesn't support but IE7 and IE8 do (child >, adjacent sibling +, general sibling ~) to hide both rules from IE6. This borders on "hacky", but your situation is one where the child combinator > fits very well, so it can be integrated organically rather than hacked in like the famous html > body filter:

    div > span.question {
        visibility: hidden;
    }
    div:hover > span.question {
        visibility: visible;
    }
    

Updated fiddle