All articles
CSS reference

The CSS :not() Selector: A Complete Guide

How the CSS :not() selector works, why it has zero specificity rules of its own, and practical patterns for excluding elements without extra classes.

6 min read - Updated 2026-06-18

The :not() pseudo-class matches every element that does not match the selector you pass it. It is the cleanest way to style "everything except" without adding negation classes by hand - but its specificity behaves in a way that surprises a lot of developers.

What :not() does and how to write it

Pass :not() a selector and it inverts the match. Modern browsers accept a full selector list, so you can exclude several things at once instead of chaining multiple :not() calls.

li:not(.active) - every list item that is not active

input:not([type="checkbox"]) - all inputs except checkboxes

:not(h1, h2, h3) - anything that is not a top-level heading

a:not(:last-child) - every link except the final one

The specificity gotcha

The :not() pseudo-class itself adds no specificity - but the selector inside it does. That means :not(.foo) carries the weight of a class selector, which can quietly make a rule stronger than you expected and override styles you wanted to win.

div:not(.x) has the specificity of div plus a class, not just div

Specificity comes from the heaviest selector in the argument list

Use it to remove unwanted resets without an !important arms race

Inspect the cascade live to confirm which rule actually wins

Real-world patterns

Negation shines for spacing, dividers, and form states where you want a default applied to a group and removed from the edges or exceptions.

Add a border to every row except the last: tr:not(:last-child)

Style links that are not buttons: a:not(.btn)

Target enabled fields only: input:not(:disabled)

Combine with :has() to exclude containers that hold a specific child

Release checklist

Replace negation utility classes with a single :not() where possible.

Check the specificity added by the selector inside :not().

Use the selector-list form to collapse multiple :not() chains.

Verify the result across breakpoints, not just one viewport.

Frequently asked questions

Does :not() increase specificity?

The :not() pseudo-class adds nothing on its own, but the selector you pass into it does. :not(.active) contributes the specificity of a class, so the overall rule is stronger than the bare element selector alone.

Can :not() take multiple selectors?

Yes. Modern browsers support a selector list inside :not(), so :not(h1, h2, h3) excludes all three. Older engines only accepted a single simple selector and required chaining like :not(h1):not(h2).

What is the difference between :not() and :is()?

:is() matches if any selector in its list matches, while :not() matches when none of them do. They are inverses, and both take their specificity from the most specific selector in the argument list.

Related guides