3

I'm sorry the title is not particularly explanatory, what I mean is as follows

What I want to achieve with the second CSS selector is "All class b elements that are descendants of class a elements but not descendants of class c elements". As you can see, the selector I've written actually selects all class b elements, regardless of whether or not they are descendants of class c elements. (I.e. I want the central div to appear blue rather than red). Why is my selector not working?

Consider the code in the following:

div {
  background: blue;
  border: 1px solid;
  margin: 20px;
  min-height: 20px;
  max-width: 300px;
}

.a :not(.c) .b {
  background: red;
}
<div class="a">
  <div>
    <div class="b">
      <div>
        <div class="c">
          <div>
            <div class="b">
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
Huangism
  • 16,278
  • 7
  • 48
  • 74
  • You can use and/or chain the child combinator (`:not(.c) > .b`) to check against the classes of specific parents, but I don't think there's an easy way to express "none of this element's parents have the class X". – Jon Uleis May 05 '21 at 20:19
  • I think https://stackoverflow.com/questions/20869061/is-the-css-not-selector-supposed-to-work-with-distant-descendants explains it, you basically just override the b which are under c. `:not(.c)` also matches the parent of the most inner b, so it is red – Huangism May 05 '21 at 20:22
  • If the structure of the code stays, you could just do `a > div > b` but it's not flexible. If you are in control of the html, I would just add/change the class name for the red box – Huangism May 05 '21 at 20:29
  • Huangism - I see what you mean when you say that :not(.c) also matches the parent of the innermost b, hence it will always be selected using the selector I've written. I believe you've solved it with the suggestion to override b which are under c. I can envisage how I will generate that code for the general case, thank you. – Mike Eustace May 05 '21 at 20:43
  • Perhaps you are going to make .a, .b and .c differ more later. But if not, perhaps use odd/even class instead? Somewhat similar discussion here https://stackoverflow.com/questions/43653574/css-odd-and-even-on-nested-elements – ak_malmo May 05 '21 at 20:45
  • @MikeEustace overriding is usually the easiest way to deal with this but I understand why you want to approach it with a one liner not rule. See the upvoted answer which is also an override which works as well. Mark it as correct if it solves the issue for you. – Huangism May 06 '21 at 13:30

2 Answers2

3

At least for this case you can do it the other way round. Force the more specific case (.a .c .b) to be blue and set .a .b to red - it will get overruled by the more specific case. enter image description here

div {
  background: blue;
  border: 1px solid;
  margin: 20px;
  min-height: 20px;
  max-width: 300px;
}

.a .c .b {
  background: blue;
  }
  
  .a .b {
    background: red;
    }
<div class="a">
  <div>
    <div class="b">
      <div>
        <div class="c">
          <div>
            <div class="b">innermost b
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
A Haworth
  • 30,908
  • 4
  • 11
  • 14
0

With this CSS sequence you should be ok: .a .b .b { background: blue; }

DEMO

div {
  background: blue;
  border: 1px solid;
  margin: 20px;
  min-height: 20px;
  max-width: 300px;
}

.a .b .b {
  background: blue;
}

.a .b {
  background: red;
}
<div class="a">
  <div>
    <div class="b">
      <div>
        <div class="c">
          <div>
            <div class="b">
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
MaxiGui
  • 6,190
  • 4
  • 16
  • 33
  • You have selected the box that the OP does not want to select and removed the box that the OP wanted haha – Huangism May 05 '21 at 20:26
  • so you want the exact opposit result ? – MaxiGui May 05 '21 at 20:26
  • I don't want anything, but the OP(original poster) wants the opposite – Huangism May 05 '21 at 20:27
  • Here you go! Let me know – MaxiGui May 05 '21 at 20:30
  • Well, if you override, it would be better if you just override the b in c. So `.a .b` is red, then `.c .b` is blue. This way you can have b inside of b which is not inside of c. i think the OP is trying to figure a way to do this with not, but there isn't a flexible way to do this with not – Huangism May 05 '21 at 20:34
  • @Huangism No it does not, because `.a .b` override `.c .b` as `.a` is over `.c` Try it yourself – MaxiGui May 05 '21 at 20:39
  • https://jsfiddle.net/bdwLqgca/ i have no idea what you are talking about, the only way a b would override c b is if you put a b after c b and since you are trying to override a b, it would not make sense to define c b first – Huangism May 06 '21 at 13:25