Does :not() negation accept descendant selectors?
In Selectors Level 3, the answer would be NO. The :not()
notation accepts only simple selectors.
6.6.7. The negation
pseudo-classThe negation pseudo-class,
:not(X)
, is a functional notation taking
a simple selector (excluding the negation pseudo-class itself) as an
argument. It represents an element that is not represented by its
argument.
What is a simple selector?
From selector syntax:
A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
Nothing about a descendant selector.
HOWEVER, in Selectors Level 4, :not()
accepts complex selectors, which would include descendant combinators. Browser support is still quite weak for this specification.
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.
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.
CSS :not on the parent does not work for descendant selectors but it does for child selectors, unless you explicitly specify the parent element type
:not(#outer) .c1
means: select all elements with class c1
and which are descendants of an element which doesn't have the ID outer
.
This matches your first element, because it has class c1
, and is a descendant of body
, which doesn't have the ID outer
.
Instead, div:not(#outer) .c1
means: select all elements with class c1
and which are descendants of a div
element which doesn't have the ID outer
. This doesn't match the second element, because all its ancestors either aren't div
elements or have the ID outer
.
Fianlly, :not(#outer) > .c1
means: select all elements with class c1
and which are a child of an element which doesn't have the ID outer
. This doesn't match the third element, because its parent has the ID outer
.
CSS: using negation on * all elements
It's working, but you're telling the browser that img
elements do have to be wrapped in something. So img
tags directly inside the article
tag will not work, but anything nested e.g. in a div
will:
article *:not(figure) img { border: 2px solid red; }
<article> <img src="//placehold.it/50"> <figure class="x"> <img src="//placehold.it/50"> </figure> <div> <img src="//placehold.it/50"> </div></article>
negation pseudoclass on CSS3 does not work on childs
It works fine if you simplify the selector:
.pag > :not(p){
color:blue;
}
JS Fiddle demo.
Albeit this 'works fine' only with the caveat that you have to specify a selector, with this approach, for every parent-child relationship; which may become burdensome.
I suspect that it's the simplicity that's required:
The negation pseudo-class, :not(X), is a functional notation taking a simple selector (excluding the negation pseudo-class itself) as an argument. It represents an element that is not represented by its argument.
A 'simple selector' is defined as:
either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
This seems to imply that any selector incorporating combinators (such as white-space, >
, +
or ~
, among others) is not 'simple', unfortunately.
References:
- Negation (
:not()
) pseudo-class. - Simple selector definition.
CSS :not() not working properly
Try this and there you go:
.header-container > a {
display:none;
}
Thanks!
Negative selecting without direct path in CSS
See, there's a problem here: the first part of this selector will be applied to any element in the second selector's match ancestor chain (in attempt to match the whole rule). Consider the following:
:not(.parent) .child { color: blue;}
<div class="parent"> <div class="child"> Which color am I? </div></div>
CSS :not selector is not applying correctly
In CSS 3, more specifically Selectors Level 3:
The negation pseudo-class, :not(X), is a functional notation taking a simple selector (excluding the negation pseudo-class itself) as an argument.
The key here being simple selector
. :not
only access simple selectors like .classsName
, not things with a ,
, or .className .child
.
Note however that this has been updated in Selectors Level 4:
The negation pseudo-class, :not(), is a functional pseudo-class taking a selector list as an argument.
Note the change of simple selector
to selector list
. That means that what you are trying to do will be possible, but only in browsers implementing the new spec.
You can always apply the styles broadly and then revert them:
* {
color: red
}
.reset-this, .reset-this * {
color: black;
}
But that is pretty terrible and gross and ugly. As you commented, it would be much better to design your class structures to avoid this.
Related Topics
Css: Transform: Translate(-50%, -50%) Makes Texts Blurry
Tint Image Using CSS Without Overlay
How Is "Grid-Template-Rows: Auto Auto 1Fr Auto" Interpreted
Chrome:How to Turn Off User Agent Stylesheet Settings
Django Templates: Group Items in Threes
Firefox @Font-Face with Local File - Downloadable Font: Download Failed
Importance of CSS Stylesheet Hierarchy
Difference Between "-Webkit-Text-Fill-Color" and "Color"
How to Make Card-Columns Order Horizontally
Table Border Color in CSS with Border Collapse
Css: Background Image Does Not Fill When Scrolling
Webkit Transform Blocking Link
Bootstrap 3 Align Text to Bottom of Div
When Using @Media Queries, Does a Phone Load Non-Relevent Queries and Images
Is Vertical Text-Overflow Possible with CSS3
How to Rotate Text Left 90 Degree and Cell Size Is Adjusted According to Text in HTML