Home > Blockchain >  CSS :not() selector not working as expected (nested)
CSS :not() selector not working as expected (nested)

Time:06-10

G'day all,

I'm once again struggling with :not(), it does not behave as I expect it to. So I created the below fiddle to allow us to start at the same point.

The Question

How do I make the middle grouping of links (under the Blue text) all blue in this example using the :not() selector.

Reference Code

Example Preface: This is a simplified example. I'm not looking for someone to say "Dude, you can move the .red class and it'll work like you want. No :not() at all." ... I'm trying to work out :not() here.

Testing example - https://jsfiddle.net/2tbwkcyg/1/

The structure is

<div> <!-- control group | green -->
    Green<br>
    <nav>Nav: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></nav>
    <div>Div: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></div>
    Direct: <a href="/">Testing Link</a> | <a href="/">Testing Link</a>
</div> <!-- /control group | green -->
<div >
  <div >
    Blue<br>
    <nav>Nav: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></nav>
    <div>Div: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></div>
    Direct: <a href="/">Testing Link</a> | <a href="/">Testing Link</a>
  </div> <!-- /blue -->
  <div>
    Red<br>
    <nav>Nav: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></nav>
    <div>Div: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></div>
    Direct: <a href="/">Testing Link</a> | <a href="/">Testing Link</a>
  </div>
</div> <!-- /red -->

while the (relevant) CSS is

a{color:green}
.blue a{color:blue}
.red :not(.blue) a{color:red}

Expected Results

Due to that last line in the CSS, I'm expecting the middle group of links to be blue, because - it's in the .red section, and they are within the .blue class.

Therefore, the expected result is:

  • Six Green links
  • Six Blue links
  • Six Red links that is, three x two of each colour.

Actual Results

But with that CSS, I get:

  • Six Green links
  • Four Red links Two Blue links
  • Six Red links

I have tried many of the solutions & suggestions here on StackOverflow, such as wrapping the selector inside the :not() with double quotes, using * before :not() and the like. But none of that appears to work. (None of which are noted on the definition btw: https://developer.mozilla.org/en-US/docs/Web/CSS/:not )

Point of Interest: I've just put in another row (the Direct one), and it seems to imply that the :not() part must immediately precede the next element selected - as they show as blue. While the ones another level down do not.

Browser Compatibility

All major browsers are on the table for this one.

I.E., Opera Mobile, QQ and Baidu Browsers are not considerations.

Thanks in advance! :)

-- EDIT --

@robby-cornelissen pointed out that on the MDN article I linked above it says:

This selector only applies to one element; you cannot use it to exclude all ancestors. For instance, body :not(table) a will still apply to links inside a <table>, since <tr> will match with the :not() part of the selector.

Which is sad. Because that's what I wanted. I wanted to have a negating class/selector somewhere between the defining class/selector and the subject, to prevent the rules applying - rather than setting / overriding with multiple lines.

@kmoser did however manage to make this sing a little using a >. It seems that if you "bind" the :not() to an immediate parent it works and overrides :not()'s implied relationship with the immediate child.

CodePudding user response:

I think a tag is not in div it is inside nav so we can use

.red :not(.blue) nav a { color: red }

or you can make another div for blue not inside red

CodePudding user response:

:not is working as expected (well, IMHO).

When you set:

.red :not(.blue) a {
  color: red;
}

You are saying 'when you find an element with class red make any link within any element that is a child, grandchild, great-grandchild etc that does not have class blue have color red'.

So the div and the nav which are children of the blue div are selected.

Then we may question selectivity and cascading.

Turns out that

.red :not(.blue) a {
  color: red;
}

and

.red .blue a {
  color: blue
}

have the same weight selectivity wise (which seems logical to me).

So here's your code but with these two settings swapped round:

a {
  color: green
}

.red :not(.blue) a {
  color: red;
}

.red .blue a {
  color: blue
}
<div>
  <!-- control group | green -->
  Green<br>
  <nav>Nav: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></nav>
  <div>Div: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></div>
  Direct: <a href="/">Testing Link</a> | <a href="/">Testing Link</a>
</div>
<!-- /control group | green -->
<div >
  <div >
    Blue<br>
    <nav>Nav: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></nav>
    <div>Div: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></div>
    Direct: <a href="/">Testing Link</a> | <a href="/">Testing Link</a>
  </div>
  <!-- /blue -->
  <div>
    Red<br>
    <nav>Nav: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></nav>
    <div>Div: <a href="/">Testing Link</a> | <a href="/">Testing Link</a></div>
    Direct: <a href="/">Testing Link</a> | <a href="/">Testing Link</a>
  </div>
</div>
<!-- /red -->

  • Related