Negative selecting without direct path in CSS

I want the following selector to match only those <span> elements that are direct children of '.grand-grand-child' and not descendants of '.grand-grand-parent':

:not(.grand-grand-parent) .grand-grand-child > span { 
  color: blue; 
}

But it fails to apply the rule. Is it possible to solve the problem without Javascript? In my experience, :not rules at the beginning have to be followed with direct path made with > signs. Am I right?

1 answer

  • answered 2018-01-11 20:04 raina77ow

    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.