See, there's a problem here: the first part of this selector will be applied to any element in the second selector's match ancestor chain (in attempt to match the whole rule). Consider the following:
:not(.parent) .child {
color: blue;
}
<div class="parent">
<div class="child">
Which color am I?
</div>
</div>
And the answer is blue, even though that .child
element is clearly matched by .parent .child
rule. The problem is, this rule reads as
match any element with class 'child' if one of its ancestors is without class 'parent'
And of course, it has such an ancestor - <body>
element. Now compare with this fragment:
:not(.parent) > .child {
color: blue;
}
<div class="parent">
<div class="child">
Which color am I?
</div>
</div>
And now the answer is black, as the selector reads as...
match any element with class 'child' if its direct parent is without class 'parent'
Another way will be opened when browsers start supporting CSS Selectors Level 4 negation spec, allowing something more than simple selector as :not
argument. It'll be possible to write something like:
.child:not(.parent *) { /* */ }
And now if any element is ancestor chain of .child
matches .parent
, it's not matched. But both Chrome and Firefox at the moment of writing still lack support of this feature - they only support CSS Level 3 negation.