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
Benji
Your life OS
The companion app that keeps every area of your world in sync.
Zero to Shipped
Ship products, not side projects
The ultimate Next.js boilerplate for building and launching real products.
DMX
Mindful Twitter/X
The intentional X client for macOS. Reclaim your attention span.
Sotto
Voice-to-text for macOS
Speak naturally. Type instantly. 100% local & private.
Passlock
Password manager with willpower
Lock passwords with time delays, word challenges, or hand the keys to someone you trust.
Glink
Changelogs that slap
Beautiful changelogs and roadmaps for your product.
JoinRepo
GitHub access control
Monetize your GitHub repositories with ease.
Tubely
YouTube Studio for Mac
Manage multiple YouTube channels in one native app.
JustWrite
Distraction-free writing
A minimal writing app that helps you focus on what matters.