How Does the CSS :not() Pseudo-Class Work?

The CSS :not() pseudo-class, often called the negation pseudo-class, allows developers to apply styles to elements that do not match a specific selector or list of selectors. By accepting one or more arguments, it inverts the matching logic, preventing selected styles from applying to targeted exceptions. This article explores the syntax, functionality, specificity rules, and practical use cases of :not() in modern web design.

Syntax and Basic Usage

The :not() pseudo-class takes a selector or a comma-separated list of selectors as its argument:

selector:not(exception-selector) {
  /* styles */
}

When the browser evaluates this rule, it targets any element matching the initial selector as long as it does not match the exception-selector enclosed inside the parentheses.

Styling Lists Without the Last Item

A classic use case involves applying bottom borders or margins to a list of items while excluding the final element:

li:not(:last-child) {
  margin-bottom: 12px;
  border-bottom: 1px solid #e0e0e0;
}

This approach eliminates the need to apply styles to every list item and subsequently reset the last item using an overriding rule.

Multi-Selector Support

In modern CSS (Selectors Level 4), :not() supports comma-separated argument lists. This allows developers to exclude multiple element types or classes within a single declaration:

button:not(.primary, .secondary, [disabled]) {
  background-color: transparent;
  color: #333;
}

This rule applies transparent backgrounds and dark text to buttons that do not carry the .primary class, the .secondary class, or the disabled attribute.

Specificity Rules of :not()

Understanding how :not() interacts with CSS specificity is essential for avoiding unintended style overrides.

For example:

/* Specificity: 0-0-1 (tag) + 0-1-0 (class inside :not) = 0-1-1 */
p:not(.highlight) {
  color: #555;
}

/* Specificity: 0-0-1 (tag) + 1-0-0 (ID is the highest inside :not) = 1-0-1 */
p:not(.highlight, #featured) {
  color: #555;
}

Because the argument with the highest specificity determines the total weight of the selector, combining low-specificity elements with IDs inside :not() will significantly increase the rule's overall specificity.

Important Limitations

While powerful, the negation pseudo-class adheres to a few strict constraints:

Using the :not() pseudo-class streamlines CSS by reducing code repetition and eliminating unnecessary selector overrides across modern stylesheets.