CSS :not() Pseudo-Class
The CSS :not() pseudo-class, also called the negation pseudo-class, matches elements that do not match a specified selector or selector list. It allows developers to exclude particular elements, classes, attributes, or states from a CSS rule without adding extra classes to the HTML.
:not() Syntax
selector:not(argument) {
property: value;
}
The :not() pseudo-class accepts a selector or a comma-separated list of selectors. The element must match the selector outside :not() and must not match any selector inside it.
Basic Example
p:not(.highlight) {
color: #333;
}
This rule selects paragraph elements that do not have the highlight class.
Multiple Selectors
p:not(.highlight, .warning) {
color: #333;
}
This rule selects paragraphs that have neither the highlight class nor the warning class.
Functional Pseudo-Class
The parentheses are required because :not() is a functional pseudo-class. Its argument must be a valid selector list.
Selector List Behavior
The argument uses a regular, unforgiving selector list. If any selector in the list is invalid or unsupported, the entire selector can become invalid. To tolerate unsupported alternatives, use :is() or :where() where appropriate.
How :not() Works
The :not() pseudo-class filters elements out of an existing selector match.
HTML Example
<p>Regular paragraph</p>
<p class="highlight">Highlighted paragraph</p>
<p>Another regular paragraph</p>
CSS Example
p:not(.highlight) {
color: #006699;
}
The first and third paragraphs match the selector. The second paragraph is excluded because it has the highlight class.
Matching Process
The browser first considers paragraphs matching p. It then excludes any paragraph that matches .highlight.
No HTML Changes Required
The exclusion is determined by CSS. You do not need to add a separate class to every paragraph that should receive the styling.
Not a JavaScript Filter
The pseudo-class affects CSS selector matching. It does not remove elements from the document or change their HTML attributes.
Excluding Classes
One of the most common uses of :not() is to style elements that do not have a particular class.
CSS Example
.button:not(.disabled) {
background-color: #006699;
color: #fff;
}
This rule selects elements with the button class unless they also have the disabled class.
HTML Example
<button class="button">Save</button>
<button class="button disabled">Unavailable</button>
Only the first button matches the selector.
Class vs. Disabled State
A class named disabled does not disable a button's behavior. For actual disabled form controls, use the HTML disabled attribute and the :disabled pseudo-class.
button:not(:disabled) {
cursor: pointer;
}
This rule targets buttons that are not disabled.
Excluding Element Types
The :not() pseudo-class can exclude specific HTML element types.
CSS Example
article > :not(h2) {
margin-top: 12px;
}
This rule selects direct children of an article except <h2> elements.
HTML Example
<article>
<h2>Article Heading</h2>
<p>First paragraph.</p>
<p>Second paragraph.</p>
</article>
The paragraphs match the selector, while the heading is excluded.
Exclude Multiple Element Types
article > :not(h2, h3) {
margin-top: 12px;
}
This rule excludes both second-level and third-level headings.
Universal Matching
When :not() is used without a preceding type selector, it can match any eligible element that does not match the excluded selector.
Multiple Selectors
Selectors Level 4 allows :not() to accept multiple selectors separated by commas.
CSS Example
li:not(.active, .disabled, .hidden) {
color: #006699;
}
This rule selects list items that do not have any of the three excluded classes.
Equivalent Selector
li:not(.active):not(.disabled):not(.hidden) {
color: #006699;
}
Both selectors match the same elements, although their specificity differs.
Important Rule
An element is excluded if it matches any selector in the argument list. It must fail to match every listed selector to satisfy :not().
Browser Compatibility
Older browsers that support only the original single-selector form may not support comma-separated selector lists inside :not().
Excluding Attributes
The :not() pseudo-class can be combined with attribute selectors to exclude elements based on their attributes.
Links Without target
a:not([target]) {
color: #006699;
}
This rule selects anchor elements that do not have a target attribute, including anchors without an href attribute.
Inputs Without required
input:not([required]) {
border-color: #999;
}
This rule selects input elements without the required attribute.
Exclude a Specific Attribute Value
input:not([type="hidden"]) {
border: 1px solid #ccc;
}
This rule excludes input elements whose type attribute is explicitly set to hidden.
Multiple Attribute Conditions
input:not([disabled], [readonly]) {
background-color: #fff;
}
This rule selects input elements that have neither the disabled nor the readonly attribute.
Excluding Element States
The :not() pseudo-class can exclude elements based on other pseudo-class states.
Enabled Buttons
button:not(:disabled) {
background-color: #006699;
color: #fff;
}
This rule selects buttons that are not disabled.
Unchecked Checkboxes
input[type="checkbox"]:not(:checked) {
outline: 1px solid #999;
}
This rule selects checkboxes that are not checked.
Elements Not Being Hovered
.card:not(:hover) {
box-shadow: none;
}
This rule applies while a card is not being hovered.
Invalid Inputs
input:not(:valid) {
border-color: #cc3333;
}
This rule selects inputs that do not match :valid. For form controls, :invalid is usually clearer when the goal is to style invalid values.
Complex Selectors and Combinators
Selectors Level 4 allows complex selectors inside :not(), including selectors that contain combinators.
Descendant Selector
p:not(article p) {
color: #006699;
}
This rule selects paragraphs that are not descendants of an <article> element.
Child Combinator
p:not(section > p) {
margin-bottom: 16px;
}
This rule excludes paragraphs that are direct children of a <section> element.
Combining Conditions
.content p:not(.intro, .note) {
line-height: 1.6;
}
This rule selects paragraphs inside .content except those with the intro or note class.
Browser Support
Complex selectors inside :not() are a newer capability than the original single simple selector syntax. Test compatibility when supporting older browsers.
Nested :not() Selectors
The :not() pseudo-class can contain another :not() pseudo-class.
CSS Example
p:not(:not(.highlight)) {
color: #006699;
}
This double negation selects paragraphs with the highlight class.
Equivalent Selector
p.highlight {
color: #006699;
}
The simpler selector is easier to read and produces the same matches.
Multiple Negations
p:not(.intro):not(.note) {
color: #333;
}
This rule selects paragraphs that have neither the intro class nor the note class.
Readability
Avoid unnecessary nested negations. Use direct selectors whenever they express the intended condition more clearly.
:not() vs. :is() and :where()
These functional pseudo-classes accept selector lists but have different matching and specificity behavior.
Comparison
| Pseudo-Class | Behavior |
|---|---|
:not() |
Matches elements that do not match any selector in its argument list. |
:is() |
Matches elements that match at least one selector in its argument list. |
:where() |
Matches like :is() but contributes zero specificity. |
CSS Example
p:not(.intro, .note) {
color: #333;
}
:is(h2, h3) {
color: #006699;
}
:where(h2, h3) {
margin-bottom: 12px;
}
The first rule excludes paragraphs with particular classes. The second and third rules match selected heading types.
Choosing a Selector
Use :not() to exclude matches, :is() to group matching alternatives, and :where() when grouping selectors without increasing specificity.
:not() Specificity
The :not() pseudo-class does not add its own specificity. Its specificity is determined by the most specific selector in its argument list.
Specificity Examples
| Selector | Specificity |
|---|---|
:not(p) | 0-0-1 |
p:not(.intro) | 0-1-1 |
p:not(.intro, #featured) | 1-0-1 |
li:not(:first-child) | 0-1-1 |
p:not(.intro):not(.note) | 0-2-1 |
p:not(:where(.intro, .note)) | 0-0-1 |
Important Detail
p:not(.intro, #featured) {
color: #006699;
}
The ID selector in the argument list gives this selector ID-level specificity, even when an element is excluded only because it does not match either argument.
Reducing Specificity
p:not(:where(.intro, #featured)) {
color: #006699;
}
Wrapping the exclusions in :where() allows the exclusion logic to remain while reducing the specificity contributed by the argument to zero.
Practical Uses
The :not() pseudo-class is useful when most elements should receive a style but certain elements need to be excluded.
Exclude the Last Item
li:not(:last-child) {
border-bottom: 1px solid #ccc;
}
Add separators between list items without adding a border to the last item.
Exclude a Featured Card
.card:not(.featured) {
background-color: #f5f5f5;
}
Apply a standard background to cards except the featured card.
Exclude Disabled Controls
button:not(:disabled) {
cursor: pointer;
}
Apply a pointer cursor only to buttons that are not disabled.
Exclude Specific Input Types
input:not([type="checkbox"], [type="radio"]) {
padding: 8px;
}
Apply padding to input elements except checkboxes and radio buttons.
Exclude Introductory Paragraphs
article p:not(.lead) {
font-size: 1rem;
}
Apply standard text sizing to paragraphs except those marked as lead paragraphs.
Limitations
The :not() pseudo-class is powerful, but its matching behavior and specificity require care.
It Does Not Remove Elements
The pseudo-class excludes elements from a CSS selector match. It does not remove elements from the DOM or hide them automatically.
Selector Lists Must Be Valid
Invalid selector syntax can affect matching. Browser support for newer selector-list features also varies.
Pseudo-Elements Are Not Allowed
Pseudo-elements such as ::before and ::after cannot be used as arguments to :not().
Specificity Can Increase
An ID selector inside :not() can increase specificity even when the matched element does not have that ID.
Broad Selectors Can Match Unexpected Elements
:not(p) {
color: #006699;
}
This rule matches every eligible element that is not a paragraph, including elements such as <html>, <body>, headings, and links.
Not a Parent Selector by Itself
The :not() pseudo-class does not independently select a parent based on its children. Combine it with :has() when a relationship-based exclusion is needed.
Best Practices
- Use
:not()when excluding a small number of elements from a broader selector. - Include an appropriate type or class selector to avoid matching unintended elements.
- Use comma-separated selector lists when they improve readability and browser support is sufficient.
- Remember that
:not()uses the specificity of its most specific argument. - Use
:where()inside:not()when low specificity is desirable. - Avoid unnecessary nested negations and overly complex selector chains.
- Use state pseudo-classes such as
:disabledinstead of classes when selecting actual element states. - Do not use pseudo-elements as arguments to
:not(). - Test complex selector lists when supporting older browsers.
:not() Example
This example displays four cards. The :not() pseudo-class applies a light blue background and blue border to cards that do not have the featured or disabled class.
HTML
<div class="not-demo">
<div class="card">Standard Card One</div>
<div class="card featured">Featured Card</div>
<div class="card">Standard Card Two</div>
<div class="card disabled">Disabled Card</div>
</div>
CSS
.not-demo .card {
padding: 12px;
margin-bottom: 8px;
border: 2px solid #ccc;
background-color: #f5f5f5;
}
.not-demo .card:not(.featured, .disabled) {
border-color: #006699;
background-color: #eaf6fc;
color: #006699;
}
.not-demo .card.featured {
border-color: #cc9900;
background-color: #fff5d6;
}
.not-demo .card.disabled {
opacity: 0.5;
}
Browser Result
Note: Standard Card One and Standard Card Two receive the blue styling. The Featured Card and Disabled Card are excluded from the :not() rule and retain their separate styles.
Browser Support
Baseline: Widely available. The :not() pseudo-class is supported in all major modern browsers. The original single simple selector syntax has long-standing support, while comma-separated selector lists and complex selectors were introduced in Selectors Level 4 and require more recent browser versions.
For current compatibility information, visit Can I Use? .
Specifications
The :not() pseudo-class is defined in CSS Selectors Level 4 as the negation pseudo-class. It accepts a selector list and matches elements that do not match any of its arguments.
