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>
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>
CSS negation pseudo-class :not() for parent/ancestor elements
Doesn't this read, "Select all
h1
elements that have an ancestor that is not adiv
element...?"
It does. But in a typical HTML document, every h1
has at least two ancestors that are not div
elements — and those ancestors are none other than body
and html
.
This is the problem with trying to filter ancestors using :not()
: it just doesn't work reliably, especially when the :not()
is not being qualified by some other selector such as a type selector or a class selector, e.g. .foo:not(div)
. You'll have a much easier time simply applying styles to all h1
elements and overriding them with div h1
.
In Selectors 4, :not()
has been enhanced to accept full complex selectors containing combinators, including the descendant combinator. Whether this will be implemented in the fast profile (and thus CSS) remains to be tested and confirmed, but once it is implemented, then you will be able to use it to exclude elements with certain ancestors. Due to how selectors work, the negation has to be done on the element itself and not the ancestor in order to work reliably, and therefore the syntax will look a little different:
h1:not(div h1) { color: #900; }
Anyone who's familiar with jQuery will quickly point out that this selector works in jQuery today. This is one of a number of disparities between Selector 3's :not()
and jQuery's :not()
, which Selectors 4 seeks to rectify.
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.
Is the CSS :not() selector supposed to work with distant descendants?
Is this supposed to work like I think it should?
No, the behavior you're seeing is correct.
In your last example, although the <blockquote>
contains a <p>
, it's the <blockquote>
itself that's matching *:not(p)
, as well as the condition that it must be a descendant of the <div>
, which it is. The style is applied only to the <blockquote>
, but it is then inherited by the <p>
inside it.
The <p>
element itself still counts against the negation, so the <p>
itself is still being excluded from your selector. It's just inheriting the text color from its parent, the <blockquote>
element.
Even if none of its relatively close ancestors matched the selector, you have elements like html
and body
to worry about as well — although you could probably just tack on a body
selector in the very beginning:
body div...
This is why I often strongly advise against using the :not()
selector for filtering descendants, especially when not qualified with a type selector (like div
in your example). It doesn't work the way most people expect it to, and the use of inherited properties like color
only serves to compound the problem, on top of making it even more confusing for authors. See my answers to these other questions for more examples:
- Why doesn't this CSS :not() declaration filter down?
- CSS negation pseudo-class :not() for parent/ancestor elements
The solution to the problem described is to simply apply a different color to <p>
elements. You won't be able to simply exclude them with a selector because of inheritance:
/* Apply to div and let all its descendants inherit */
div {
color: red;
}
/* Remove it from div p */
div p {
color: black;
}
On Selectors Level 4: yes, :not()
has indeed been enhanced to accept full complex selectors that contain combinators. Essentially, this means (once browsers begin implementing it) you will be able to write the following selector and have it do exactly what you want:
p:not(div p) {
color: red;
}
In case anyone is interested, this works in jQuery today.
Complex CSS selector for parent of active child
Unfortunately, there's no way to do that with CSS.
It's not very difficult with JavaScript though:
// JavaScript code:
document.getElementsByClassName("active")[0].parentNode;
// jQuery code:
$('.active').parent().get(0); // This would be the <a>'s parent <li>.
CSS selector to exclude all children where any parent at ANY LEVEL has a class
Find all the elements (all
), then the elements with no-material
on the element or its parent (no
), then remove those in the second from those in the first to find those that remain (yes
).
const difference = (a, b) => a.filter(elt => b.indexOf(elt) === -1); const all = document.querySelectorAll("input");const no = document.querySelectorAll(".no-material input, input.no-material");
const yes = difference([...all], [...no]);
console.log(yes.map(elt => elt.name));
<main style="display: none;">
<!-- Not selectable --> <div class="no-material"> <input name="no-1"> </div>
<div> <input name="no-2" class="no-material"> </div>
<div> <label class="no-material"> <input name="no-3"> </label> </div>
<div> <label class="no-material"> <span> <input name="no-4"> </span> </label> </div>
<div> <label> <span class="no-material"> <input name="no-5"> </span> </label> </div>
<!-- Selectable --> <div> <input name="yes-1"> </div>
<div> <input name="yes-2"> </div>
<div> <label> <input name="yes-3"> </label> </div>
<div> <label> <span> <input name="yes-4"> </span> </label> </div>
<div> <label> <span> <input name="yes-5"> </span> </label> </div>
</main>
Related Topics
Why Is My Android Device-Width 980Px
How to Change Inline Text Height, Not Just the Line-Height
CSS Auto Numbers for Table Rows - Not First
How to Put Custom Content Like a Linebreak Inside P:Column Header
Javafx Text Styling for Dynamic Objects
Why Is CSS Calc(100%-250Px) Not Working
CSS Content Attribute for Img Tag
Can You Reference Images from CSS Without Using Relative Paths
Background-Image + Rgba() with Fallback in Ie 7-8
Css/Webkit: Background Images for Table Row
What Does "A" Stand for in Font: 0/0 A;
CSS Sprites - Not Only for Background Images
Jquery Mobile Textarea: How Does It Use 'Rows' Attribute
Line-Height Affecting Spacing Above First Line and After Last Line