Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
}
like image 637
Geesh_SO Avatar asked Oct 06 '17 15:10

Geesh_SO


People also ask

How do you exclude a class in CSS?

In CSS, to exclude a particular class, we can use the pseudo-class :not selector also known as negation pseudo-class or not selector. This selector is used to set the style to every element that is not the specified by given selector. Since it is used to prevent a specific items from list of selected items.

How does CSS decide which rule to apply?

The specificity of a CSS rule depends on its selector. The more specific the CSS selector is, the higher is the precedence of the CSS property declarations inside the CSS rule owning the selector. In general terms, the more specifically (uniquely) a CSS selector targets an HTML element, the higher is its specificity.

How do you apply CSS to all child elements except first?

This selector is used to select every element which is not the first-child of its parent element. It is represented as an argument in the form of :not(first-child) element.

How do I apply a CSS to a specific class?

To select elements with a specific class, write a period (.) character, followed by the name of the class. You can also specify that only specific HTML elements should be affected by a class. To do this, start with the element name, then write the period (.)


1 Answers

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.
like image 164
andreas Avatar answered Oct 10 '22 21:10

andreas