The :not() pseudo-class selects elements that do not match a condition. It is a negation filter for precise, exception-based styling.
01
Negation
Exclude match.
02
:not(.x)
Skip a class.
03
Chain
Multiple rules.
04
Forms
Skip buttons.
05
Lists
Skip .active.
06
Combine
With :has().
Fundamentals
Introduction
The :not() selector in CSS is a powerful pseudo-class that allows you to select elements that do not match a certain condition. It acts as a negation filter, making it easier to exclude specific elements from being styled while still targeting others.
This selector can be combined with various other selectors to give more precise control over styling.
Definition and Usage
Write :not(selector) with any valid CSS selector inside the parentheses. The rule matches elements that fail that selector test.
💡
Beginner Tip
Think of :not() as “everything except.” Instead of styling each item individually, write one rule for all li elements except those with .active: li:not(.active).
Foundation
📝 Syntax
The syntax for the :not() pseudo-class is:
syntax.css
:not(selector){/* CSS properties */}
The :not() selector accepts any valid CSS selector inside the parentheses and excludes matching elements from the rule.
:not(:placeholder-shown) excludes the empty placeholder state, so errors appear only after the user starts typing.
Tips
💬 Usage Tips
Any selector inside — Use classes, attributes, pseudo-classes, or elements in the parentheses.
Chain for multiple — :not(.a):not(.b) excludes both conditions.
Comma lists — Modern browsers support :not(.a, .b) in one call.
Pair with :has() — :not(:has(a)) selects elements without links inside.
Keep it readable — Simple inner selectors are easier to maintain than deep chains.
Watch Out
⚠️ Common Pitfalls
Performance — Overusing complex :not() selectors on large pages can slow matching.
Specificity surprises — :not(.x) adds the specificity of its argument.
Legacy IE — IE8 and below do not support :not().
Universal selector — :not(*) is rarely useful; be intentional with exclusions.
Over-nesting — Long chains like :not(.a):not(.b):not(.c) may signal a need for clearer markup.
A11y
♿ Accessibility
Do not hide meaning — Excluding elements from styles should not remove important visual cues.
Form validation — Pair delayed error styles with clear labels and ARIA where needed.
Active states — Ensure excluded “active” items still meet contrast requirements.
Focus styles — Do not use :not() to strip focus outlines from interactive elements.
🧠 How :not() Works
1
Browser finds candidates
CSS gathers elements matching the base selector before :not().
Match
2
Tests inner selector
Each candidate is checked against the selector inside the parentheses.
Filter
3
Keeps non-matches
Elements that fail the inner selector receive the styles.
Negate
=
∅
Exception-based styling
One rule covers the group; excluded items stay untouched or get their own rules.
Compatibility
🖥 Browser Compatibility
:not() is supported in all modern browsers. Internet Explorer 8 and below do not support it.
✓ Baseline · Universal support
Negation everywhere modern
:not() works in Chrome, Firefox, Safari, and Edge. Comma lists inside :not() need current browsers.
98%Modern support
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple Safari9+ · macOS & iOS
Full support
Microsoft EdgeAll versions
Full support
Internet ExplorerIE8 and below · Not supported
No support
:not() pseudo-class98% supported
Bottom line::not() is safe for modern projects; chain selectors for older browser fallbacks if needed.
Wrap Up
🎉 Conclusion
The CSS :not() selector is a versatile tool for fine-tuning styles by excluding certain elements from selection. It is especially handy for dynamic content or creating exceptions for specific classes and states.
By using :not(), you gain more precision and control, making it an essential part of any CSS toolkit.
Combine with :invalid and :placeholder-shown for forms
Keep inner selectors simple
Pair with :has() for powerful filters
❌ Don’t
Overuse complex :not() on huge documents
Rely on :not() when a dedicated class is clearer
Assume IE8 support
Nest too many chained :not() calls
Remove focus or error cues with :not()
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about :not()
Use these points when excluding elements from styles.
5
Core concepts
∅01
Negation
Exclude match.
Purpose
()02
:not(.x)
Inner selector.
Syntax
🔗03
Chain
Multiple skips.
Pattern
%04
Specificity
Counts inside.
Rule
🌐05
98% support
Modern browsers.
Compat
❓ Frequently Asked Questions
The :not() pseudo-class matches elements that do not match the selector inside the parentheses. It acts as a negation filter, letting you style everything except a specific class, tag, or state.
Write :not(selector) with a valid CSS selector inside the parentheses: li:not(.active), input:not([type=submit]), or p:not(:last-child).
In modern browsers, :not(.a, .b) accepts a comma-separated list. For older support, chain them: :not(.a):not(.b). Each :not() still takes one simple or compound selector per chain link.
:not() lets you write one broad rule with an exception built in, reducing duplicate CSS. A more specific rule works too, but :not() keeps intent clear when excluding a small subset.
All modern browsers support :not(). Internet Explorer 8 and below do not. Chained and complex selectors inside :not() have broader support in current browsers than very old IE versions.