0

I try to select all lis in the page except whose are inside a container(ascendant) with class .foo

Output: The li 22 should not be colored.

I can't use direct descendants because there could be nested lis and uls.

enter image description here

m4n0
  • 29,823
  • 27
  • 76
  • 89
Doc Kodam
  • 723
  • 6
  • 14

2 Answers2

2

It's not working because you haven't specified that it's that exact element that can't have the class. The ul element that contains the li element doesn't have that class, so that matches the :not(.foo) part of the selector.

Make sure that the :not(.foo) part applies only to the right element, for example by specifying exactly where the element is in relation to the list element:

:not(.foo) > ul > li { background: red; }
<ul>
  <li>11</li>
</ul>
<div class="foo">
  <ul>
    <li>22</li>
  </ul>
</div>
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • I can't use direct descendants because the code is dynamic, there could be nested lis and uls. – Doc Kodam Nov 21 '15 at 15:06
  • @DocKodam: Then you can use any other way to specify where the element is. If they for example are directly in the `body` element (as in the example) you can use `body > :not(.foo) li`. – Guffa Nov 21 '15 at 15:15
1

I guess css selectors are using an OR or ORELSE relation. So when you use a selector like :not(.foo) li something similar happens:

statement1: In first place it will check: is actual element's tagname is li? (true)
statement2_1:In second place it will check: is closest parents class not .foo? (true)
statement2_2:In next place it will check next parent: is next parent class not .foo (false)

Theoretically the following statement evaluates:
statement1 AND (statement2_1 ORELSE statement2_2)
true AND (true ORELSE false) => true AND true = > true

What if you just try other way:

li{
  background-color: red;
}

.foo li{
  background-color: initial;
}
<ul>
  <li>11</li>
</ul>
<div class=foo>
  <ul>
    <li>22</li>
  </ul>
</div>
Pho3nixHun
  • 820
  • 2
  • 11
  • 24
  • That's not correct. The `:not` pseudo-class can be used by itself, it doesn't have to be attached to another selector. https://developer.mozilla.org/en-US/docs/Web/CSS/%3Anot – Guffa Nov 21 '15 at 15:01
  • Like Guffa said, the not class can be used by itself, and the first ul isnt inside any div. I need to select any container. – Doc Kodam Nov 21 '15 at 15:05
  • Sorry, You're right. I've updated the answer. – Pho3nixHun Nov 21 '15 at 15:16
  • Yeah I found the logic of CSS reading the RFC. Your answer is correct now. I must used the alternative. – Doc Kodam Nov 21 '15 at 15:51
  • 1
    There is no OR relation. The `:not(.foo) li` selector is evaluated by first matching the element against `li`, and if that matches checking if it has a parent element that matches `:not(.foo)`. As the closest parent `ul` matches that, it will never consider the `div`. – Guffa Nov 21 '15 at 19:16
  • You've said almost the same, just with other words. (s stands for statement) s1: `element is li ` => `true` s2: `element's parent is :not(.foo)` => `true` s3: `element's other parent is :not(.foo)` => `false` I said: `s1 AND (s2 OR s3)` You said: `s1 AND (s2 ORELSE s3)` – Pho3nixHun Nov 23 '15 at 22:31