CSS :not() Selector

Beginner
⏱️ 6 min read
📚 Updated: Jul 2026
🎯 4 Examples
Negation

What You’ll Learn

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().

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).

📝 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.

Basic Example

not-basic.css
li:not(.active) {
  background: #f1f5f9;
  color: #334155;
}

.active {
  background: #16a34a;
  color: #fff;
}
li:not(.active) p:not(:last-child) input:not([type=submit]) :not(:has(a))

Chaining Multiple Exclusions

not-chain.css
/* Exclude submit and reset buttons */
input:not([type="submit"]):not([type="reset"]) {
  border: 2px solid #2563eb;
}

/* Modern: comma list inside one :not() */
input:not([type="submit"], [type="reset"]) {
  border: 2px solid #2563eb;
}

Syntax Rules

  • Place :not() after the element or scope: li:not(.active).
  • Chain multiple exclusions: :not(.a):not(.b).
  • Modern browsers allow comma lists: :not(.a, .b).
  • Combine with pseudo-classes: :invalid:not(:placeholder-shown).
  • Avoid overly complex selectors inside :not() for performance.

Related Selectors

  • :has() — select parents that contain a match; pair with :not(:has())
  • .class / #id — common arguments inside :not()
  • [attribute] — exclude inputs by type or state
  • :is() — opposite grouping pattern (match any in a list)

⚡ Quick Reference

QuestionAnswer
Selector typeFunctional negation pseudo-class
Syntax:not(selector)
MatchesElements that do NOT match the inner selector
Multiple exclusionsChain or use comma list (modern)
Common useSkip .active, skip button inputs, skip last child
Browser supportAll modern browsers (not IE8−)

When to Use :not()

:not() is ideal for exception-based styling:

  • Highlight exceptions — Style all list items except the active one.
  • Form fields only — Style text inputs but exclude submit and reset buttons.
  • Spacing between items — Add margin to all paragraphs except the last: p:not(:last-child).
  • Delayed validation — Show errors only after typing: :invalid:not(:placeholder-shown).
  • Empty states — Select containers without children: .card:not(:has(img)).

👀 Live Preview

Non-active items match li:not(.active); active items keep green styling:

  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5

Examples Gallery

Practice :not() with list exceptions, form inputs, paragraph spacing, and validation patterns.

📜 Core Patterns

Exclude specific classes or elements from a broad rule.

Example 1 — Style list items except .active

Apply gray background to all <li> elements that do not have the active class.

not-list.html
<style>
  li:not(.active) {
    background: #f1f5f9;
    color: #334155;
    padding: 0.65rem 0.9rem;
  }
  .active {
    background: #16a34a;
    color: #fff;
    font-weight: 600;
  }
</style>

<ul>
  <li class="active">Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li class="active">Item 4</li>
  <li>Item 5</li>
</ul>
Try It Yourself

How It Works

li:not(.active) matches every list item that lacks the active class. Items with .active are styled separately.

Example 2 — Style inputs except submit and reset

Chain :not() to exclude button-type inputs from a border rule.

not-input.css
input:not([type="submit"]):not([type="reset"]) {
  border: 2px solid #2563eb;
  padding: 0.5rem 0.75rem;
  border-radius: 0.4rem;
}
Try It Yourself

How It Works

Each chained :not() removes another type from the match. Text and email inputs get the border; submit and reset buttons do not.

📄 Spacing & Validation

Combine :not() with structural and form pseudo-classes.

Example 3 — Margin on all but the last paragraph

Add bottom spacing between paragraphs without extra gap after the final one.

not-paragraph.css
p:not(:last-child) {
  margin-bottom: 1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid #e2e8f0;
}
Try It Yourself

How It Works

p:not(:last-child) matches every paragraph except the last one in its parent, a common pattern for stacked content dividers.

Example 4 — Delayed invalid field styling

Show validation errors only after the user has typed something, using :invalid:not(:placeholder-shown).

not-validation.css
input:invalid:not(:placeholder-shown) {
  border-color: #dc2626;
  background: #fef2f2;
}

input:valid {
  border-color: #16a34a;
}
Try It Yourself

How It Works

:not(:placeholder-shown) excludes the empty placeholder state, so errors appear only after the user starts typing.

💬 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.

⚠️ 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.

♿ 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.

🖥 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 Chrome All versions · Desktop & Mobile
Full support
Mozilla Firefox All versions · Desktop & Mobile
Full support
Apple Safari 9+ · macOS & iOS
Full support
Microsoft Edge All versions
Full support
Internet Explorer IE8 and below · Not supported
No support
:not() pseudo-class 98% supported

Bottom line: :not() is safe for modern projects; chain selectors for older browser fallbacks if needed.

🎉 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.

💡 Best Practices

✅ Do

  • Use :not() for clear exceptions in broad rules
  • Chain or comma-list multiple exclusions
  • 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()

Key Takeaways

Knowledge Unlocked

Five things to remember about :not()

Use these points when excluding elements from styles.

5
Core concepts
() 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.

Practice in the Live Editor

Open the HTML editor and experiment with :not(), list exceptions, and form filters.

HTML Editor →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful