:not()

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2021.

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.

Try it

The :not() pseudo-class has a number of quirks, tricks, and unexpected results that you should be aware of before using it.

Syntax

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.

css
:not(<complex-selector-list>) {
  /* ... */
}

Description

There are several unusual effects and outcomes when using :not() that you should keep in mind when using it:

  • Useless selectors can be written using this pseudo-class. For example, :not(*) matches any element which is not an element, which is obviously nonsense, so the accompanying rule will never be applied.
  • This pseudo-class can increase the specificity of a rule. For example, #foo:not(#bar) will match the same element as the simpler #foo, but has the higher specificity of two id selectors.
  • The specificity of the :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>.
  • This selector will match everything that is "not an X". This may be surprising when used with descendant combinators, since there are multiple paths to select a target element. For instance, 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.
  • You can negate several selectors at the same time. Example: :not(.foo, .bar) is equivalent to :not(.foo):not(.bar).
  • If any selector passed to the :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.

Examples

Using :not() with valid selectors

This example shows some a few examples of using :not().

HTML

html
<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>

CSS

css
.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;
}

Result

Using :not() with invalid selectors

This example shows the use of :not() with invalid selectors and how to prevent invalidation.

HTML

html
<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>

CSS

css
/* 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;
}

Result

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.

Specifications

Specification
Selectors Level 4
# negation

Browser compatibility

Report problems with this compatibility data on GitHub
desktopmobile
Chrome
Edge
Firefox
Opera
Safari
Chrome Android
Firefox for Android
Opera Android
Safari on iOS
Samsung Internet
WebView Android
WebView on iOS
Negation pseudo-class selector (:not())
Selector list argument

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support
No support
No support

See also