CSS :Not() Selector. Apply Style If Parent Does Not Exist

CSS :not() selector. Apply style if parent does not exist

You're selecting wrong elements. No reverse lookups possible, see here:

div:not(.container1) > .myDiv {  color: red;}
<div class="container1">  <div class="myDiv">Div 1</div></div>
<div class="container2"> <div class="myDiv">Div 2</div></div>

Apply css rule on everything but not a selector and its children

This should target any direct child of .parent that doesn't have the class of child as well as its descendants:

.parent> :not(.child),
.parent> :not(.child) * {
background-color: red;
}
<div class="parent">
<div class="child">
<div>inside</div>
<div>inside2</div>
</div>
<div>outside</div>
<div>
<div>outside!</div>
</div>
</div>

css3 :not() selector to test parent's class

Combinators such as >, + and space for descendant aren't allowed within :not() in CSS; they're only allowed as a jQuery selector. You can find out more in this other question.

That said, you may be able to use :not() on the li alone, and move out the > a part; however this will depend on the structure of your ul and li elements:

li:not(.active) > a {
color: grey;
}

For example, you can always chain other selectors, such as .span3 if you want to limit it to a elements with li parents of that class only:

li.span3:not(.active) > a {
color: grey;
}

Keep in mind, though, that you can only rely on using :not() in this manner if you have control over the markup or the structure is at least predictable (e.g. you know what kind of elements the parents are). In your case for example, you're only looking at li.span3 > a, and applying styles only when the li.span3 does not have the active class. With this information you can construct a selector like one of the above, which should work as expected.

Select only elements that don't have a parent with defined class

I don't think you can use combinator selectors with :not as stated in the documentation:

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 of a table, since <tr> will match with the
:not() part of the selector.

You could try something like this:

div {  background-color: red;  padding: 5px;}
.child { background-color: green; padding: 5px;}
.dontSelect .child { background-color: initial;}
<div>  <div class="child">    Select this  </div>  <div class="dontSelect">    <div>      <div class="child">        Don't select this      </div>    </div>  </div></div>

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

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>

Is there a CSS parent selector?

There is currently no way to select the parent of an element in CSS in a way that works across all browsers.

That said, the Selectors Level 4 Working Draft includes a :has() pseudo-class that will provide this capability. It will be similar to the jQuery implementation.

li:has(> a.active) { /* styles to apply to the li tag */ }

As of 2022, it is only supported by Safari, and by Chromium browsers behind a flag.

In the meantime, you'll have to resort to JavaScript if you need to select a parent element with full cross-browser support.

What do people mean when they say theres no parent selector in css?

In order to understand what they mean you need to understand what selecting means in CSS (parent is easy :).

By selector they mean the element to which CSS applies. So, using CSS, if you have a selector (any selector), you cannot apply changes to any of the parent parts. You can only apply them to its last part. To the child (or, in some cases, to an immediate or distant following sibling).

(The simple rule here is that the part determining which element the styling will apply to is always the last part of the selector).

Let's take this simple selector:

ul { 
/* rules apply to all ul */
}

I can make a rule to style up all it's children:

ul > * { 
/* rules apply to * (all children of ul) */
}

But I cannot make a rule to style up its parent:

* < ul { 
/* rules don't apply. this is invalid */
}

Whenever I make a rule, like...

* > ul {
/* rules apply to any ul that is a child of * (any element) */
}

the style always applies to the last item in the selector, never to one of the parents.

That's why there's no parent selector in CSS. You can't style a parent based on selecting one of its children. You need to select it. Got it?


Heck, I'll give you an example.

Consider this markup, but imagine it 10 times more complex (let's assume there's a bunch of guys adding/removing parts from it so it can have huge depth):

<div>
<whatever></whatever>
</div>
<span>
<whatever></whatever>
</span>
<ul>
<li>
<whatever></whatever>
</li>
<li></li>
<li>
<whatever></whatever>
</li>
</ul>

Now, please create a CSS that would make all parents (one single level ancestors) of <whatever> have a red background, no matter where they are in DOM. Can you?

Here's some news: you can't.

The closest they got to making this happen was when :has() selector has been proposed, but it's been rejected. This selector would need the CSS parser to go back, and it always goes forward. That's why it's fast, no matter the device/browser/system. CSS is always fast.

Because it has no :has() selector (or < combinator).

Additional note: As @Maximus has noted in comments, shadow DOM elements provide a method to select the top level element of the current shadow DOM instance by using :host. It's not a proper parent selector, as it doesn't provide means to select parent elements inside the shadow DOM, but only the entry point (the contact point with the normal DOM), giving you the option to apply rules to the current shadow DOM instance and not to others.



Related Topics



Leave a reply



Submit