Geesh_SO
Geesh_SO

Reputation: 2206

Can I apply CSS only if an ancestor does not contain a certain class?

Explanation:

I'm not a CSS expert but my current attempt is this.

div:not(.classToBeAvoid) *{
    background-color:red;
}

Which in English I read as...

"Apply a red background to any element which does not have <div class="classToBeAvoid"> as an ancestor".

But nonetheless, in my test, it doesn't seem to work like this.

CodePen:

https://codepen.io/anon/pen/eGVBVb

Code:

<div class="classToBeAvoid">
  <div>
    <p>
      Shouldn't be a red background on any element around here.
    </p>
  </div>
</div>

<div>
 <p>
   Should be a red background
 </p>
</div>

div:not(.classToBeAvoid) *{
  background-color:red;
}

Upvotes: 13

Views: 5936

Answers (1)

andreas
andreas

Reputation: 16946

Your interpretation is totally correct. You are applying a red background to any <div> that is not of class classToBeAvoid. Unfortunately this also applies to child <div>s, which is the reason for your first <div> to also be red (in fact your first parent <div> isn't red, but its child).

There are several ways to solve this issue (at least with some trade-offs).


1. The general siblings selector ~

You can use the general siblings selector, which will work in your case, because your .classToBeAvoid is before the following <div> elements.

div~:not(.classToBeAvoid)

div~:not(.classToBeAvoid) {
  background-color: red;
}
<div class="classToBeAvoid">
  <div>
    <p>
      Shouldn't be a red background on any element around here.
    </p>
  </div>
</div>


<div>
  <p>
    Should be a red background
  </p>
</div>


2. No nesting

If thats not always the case (which I assume), one way would be to remove your <div> nesting to make it work.

div:not(.classToBeAvoid) {
  background-color: red;
}
<div class="classToBeAvoid">
  <p>
    Shouldn't be a red background on any element around here.
  </p>
</div>


<div>
  <p>
    Should be a red background
  </p>
</div>


3. Additional class

If you don't want to remove your <div> nesting either, you can apply classes to the top level <div>s and use these for the selector, i.e.:

.chosen:not(.classToBeAvoid)

.chosen:not(.classToBeAvoid) {
  background-color: red;
}
<div class="chosen classToBeAvoid">
  <div>
    <p>
      Shouldn't be a red background on any element around here.
    </p>
  </div>
</div>


<div class="chosen">
  <p>
    Should be a red background
  </p>
</div>


4. Direct child selector >

If you also don't want to give every top level <div> an additional class, you can use the parent with the direct child selector >:

body>div:not(.classToBeAvoid)

body>div:not(.classToBeAvoid) {
  background-color: red;
}
<div class="classToBeAvoid">
  <div>
    <p>
      Shouldn't be a red background on any element around here.
    </p>
  </div>
</div>


<div>
  <p>
    Should be a red background
  </p>
</div>


5. Inheritance

Furthermore you can use your selector div:not(.classToBeAvoid) as you already did and in addition make sure, that child <div>s inherit the behaviour of .classToBeAvoid:

.classToBeAvoid div {
  background-color: inherit;
}

div:not(.classToBeAvoid) {
  background-color: red;
}
.classToBeAvoid div {
  background-color: inherit;
}
<div class="classToBeAvoid">
  <div>
    <p>
      Shouldn't be a red background on any element around here.
    </p>
  </div>
</div>


<div>
  <p>
    Should be a red background
  </p>
</div>


  1. or 5. are what I would prefer in your case.

Upvotes: 10

Related Questions