This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
The :not() CSS pseudo-class represents elements that do not match a list of selectors. Since it prevents specific items from being selected, it is known as the negation pseudo-class.
p:not(.irrelevant) {
font-weight: bold;
}
p > strong,
p > b.important {
color: crimson;
}
p > :not(strong, b.important) {
color: darkmagenta;
}
<p> <b>Mars</b> is one of the most Earth-like planets. <b>Mars</b> day is almost the same as an Earth day, only <strong>37 minutes</strong> longer. </p> <p class="irrelevant"> <b class="important">NASA</b>'s Jet <del>Momentum</del> Propulsion Laboratory is designing mission concepts to survive the <b>Venus</b> extreme temperatures and atmospheric pressure. </p>
The :not() pseudo-class has a number of quirks, tricks, and unexpected results that you should be aware of before using it.
:not(<complex-selector-list>) {
/* ... */
}
The :not() pseudo-class requires a selector list, a comma-separated list of one or more selectors, as its argument. The list must not contain a pseudo-element, but any other simple, compound, and complex selectors are allowed.
There are several unusual effects and outcomes when using :not() that you should keep in mind when using it:
:not(*) matches any element which is not an element, which is obviously nonsense, so the accompanying rule will never be applied.#foo:not(#bar) will match the same element as the simpler #foo, but has the higher specificity of two id selectors.:not() pseudo-class is replaced by the specificity of the most specific selector in its comma-separated argument of selectors; providing the same specificity as if it had been written :not(:is(argument)).:not(.foo) will match anything that isn't .foo, including <html> and <body>.
body :not(table) a will still apply to links inside a <table>, since <tr>, <tbody>, <th>, <td>, <caption>, etc. can all match the :not(table) part of the selector. To avoid this, you can use body a:not(table a) instead, which will only apply to links that are not descendants of a table.:not(.foo, .bar) is equivalent to :not(.foo):not(.bar).:not() pseudo-class is invalid or not supported by the browser, the whole rule will be invalidated. The effective way to overcome this behavior is to use :is() pseudo-class, which accepts a forgiving selector list. For example :not(.foo, :invalid-pseudo-class) will invalidate a whole rule, but :not(:is(.foo, :invalid-pseudo-class)) will match any (including <html> and <body>) element that isn't .foo.This example shows some a few examples of using :not().
<p>I am a paragraph.</p> <p class="fancy">I am so very fancy!</p> <div>I am NOT a paragraph.</div> <h2> <span class="foo">foo inside h2</span> <span class="bar">bar inside h2</span> </h2>
.fancy {
text-shadow: 2px 2px 3px gold;
}
/* <p> elements that don't have a class `.fancy` */
p:not(.fancy) {
color: green;
}
/* Elements that are not <p> elements */
body :not(p) {
text-decoration: underline;
}
/* Elements that are not <div>s or `.fancy` */
body :not(div):not(.fancy) {
font-weight: bold;
}
/* Elements that are not <div>s or `.fancy` */
body :not(div, .fancy) {
text-decoration: overline underline;
}
/* Elements inside an <h2> that aren't a <span> with a class of `.foo` */
h2 :not(span.foo) {
color: red;
}
This example shows the use of :not() with invalid selectors and how to prevent invalidation.
<p class="foo">I am a paragraph with .foo</p> <p class="bar">I am a paragraph with .bar</p> <div>I am a div without a class</div> <div class="foo">I am a div with .foo</div> <div class="bar">I am a div with .bar</div> <div class="foo bar">I am a div with .foo and .bar</div>
/* Invalid rule, does nothing */
p:not(.foo, :invalid-pseudo-class) {
color: red;
font-style: italic;
}
/* Select all <p> elements without the `foo` class */
p:not(:is(.foo, :invalid-pseudo-class)) {
color: green;
border-top: dotted thin currentColor;
}
/* Select all <div> elements without the `foo` or the `bar` class */
div:not(.foo, .bar) {
color: red;
font-style: italic;
}
/* Select all <div> elements without the `foo` or the `bar` class */
div:not(:is(.foo, .bar)) {
border-bottom: dotted thin currentColor;
}
The p:not(.foo, :invalid-pseudo-class) rule is invalid because it contains an invalid selector. The :is() pseudo-class accepts a forgiving selector list, so the :is(.foo, :invalid-pseudo-class) rule is valid and equivalent to :is(.foo). Thus, the p:not(:is(.foo, :invalid-pseudo-class)) rule is valid and equivalent to p:not(.foo).
If :invalid-pseudo-class was a valid selector, the first two rules above would still be equivalent (the last two rules showcase that). The use of :is() makes the rule more robust.
| Specification |
|---|
| Selectors Level 4> # negation> |
| Desktop | Mobile | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | WebView Android | WebView on iOS | |
:not |
1 | 12 | 1 | 9.5 | 3.1 | 18 | 4 | 10.1 | 2 | 1.0 | 2 | 2 |
selector_list |
88 | 88 | 84 | 74 | 9 | 88 | 84 | No | 9 | 15.0 | 88 | 9 |
Other functional CSS pseudo-classes:
How :not() chains multiple selectors on MDN blog (2023)
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/CSS/:not