6

I have this small HTML:

<div id="column">
    <div class="ticker">
        <ul>
            <li>Item 1</li>
        </ul>
    </div>
</div>

For ul elements outside of the .ticker class, but inside of the #column id exists this CSS:

#column ul:not(.a):not(.b) {
    margin: 1em;
}

But inside the .ticker class I don't want this margin. So I thought I could use:

#column .ticker ul {
    margin: 0;
}

That said, I know that the specificity of the first CSS selector is higher because of the two :not() pseudo classes. But to get a higher specificity I had to append those two :not() in the second CSS snippet to the ul, too. So that works:

#column .ticker ul:not(.c):not(.d) {
    margin: 0;
}

Isn't that stupid? In fact it doesn't matter what you use in the two :not()pseudo classes. They just have to be there. This doesn't make any sense to me.

Is that simply a part of CSS3 which is not perfect or is there a solution which my brain didn't come up with yet?

See it in action here: http://jsfiddle.net/9BDw5/2/

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Juuro
  • 1,487
  • 5
  • 16
  • 27
  • You have calculated the CSS specificity correctly so your CSS (though a bit awkward perhaps) is good. There might be a better way of designing the overall CSS scheme, but it depends in part on the HTML structure of the web page in question. – Marc Audet May 22 '14 at 19:01
  • Yes - psuedoclasses and psuedoelements have the same specificity as their real counterparts. This is not a CSS issue so much as it's a CSS and markup design/practices issue. – Ennui May 22 '14 at 19:13

3 Answers3

7

It's not just you; this is indeed one of the fundamental pitfalls of specificity as a CSS concept.

A simpler solution that is equally valid would be to repeat your .ticker class selector so you have this:

#column .ticker.ticker ul {
    margin: 0;
}

This way you do not have to modify your element to add an extra class just for the sake of increasing selector specificity.

The spec verifies this:

Note: Repeated occurrances of the same simple selector are allowed and do increase specificity.

On a side note, remember that the specificity of the :not() pseudo-class is strictly defined (in the same section of the spec) as equal to that of its argument. So :not(#id) and #id have the same specificity, and likewise for :not(E):not(.a) and E.a. The :not portion does not count at all, not even as a pseudo-class.

This limitation in specificity will be addressed in Selectors 4, which enhances :not() to accept a comma-delimited list of selectors. The specificity of a :not() that contains a selector list will be that of the most specific selectors in the list, so the specificity of ul:not(.c, .d) is equal to 1 type selector and 1 class selector, compared to ul:not(.c):not(.d) which is equal to 1 type selector and 2 class selectors. This makes it tremendously useful in excluding any number of classes from a match.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
0

Here is an alternative, and somewhat cleaner approach.

Add a fictitious class name to your div.ticker element:

<div id="column">
    <ul>
        <li>Outside Item 1</li>
    </ul>
    <div class="ticker extra-tag">
        <ul>
            <li>Item 1</li>
        </ul>
    </div>
</div>

and modify the CSS as follows:

#column ul:not(.a):not(.b) {
    margin-left: 1em;
}

#column .ticker.extra-tag ul {
    margin-left: 0;
}

So, the specificity of the first rule is 1-1-2 and for the second rule 1-1-2.

The two :not() count as two classes, so you need to have at least two classes in the second rule, which I implemented by using the fictitious class name .extra-tag.

The fictitious class is probably more computationally efficient than adding the extra :not() pseudo-class.

See demo at: http://jsfiddle.net/audetwebdesign/7beNx/

Learn more about CSS specificity at: http://www.w3.org/TR/css3-selectors/#specificity

Marc Audet
  • 46,011
  • 11
  • 63
  • 83
  • You don't even have to add the extra class - you can simply repeat `.ticker` so you have `#column .ticker.ticker ul`, which is perfectly acceptable and does give the same specificity bonus. (Shall I post it as a separate answer since it's quite different from yours?) – BoltClock Jun 23 '14 at 10:14
  • @BoltClock Interesting variation, please post with comments, this trick would be very useful for cases where you may not be able to add the extra class name. – Marc Audet Jun 23 '14 at 11:13
0

As mentioned above chaining the :not() pseudo-class increases specificity by one each time.

This article explains it very nicely

sidonaldson
  • 24,431
  • 10
  • 56
  • 61