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.
- The
:not()pseudo-class itself contributes zero specificity. - The specificity of
:not()equals the specificity of the most specific selector in its argument list.
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:
- No self-nesting: You cannot nest a
:not()inside another:not(), such as:not(:not(.active)). - No pseudo-elements: Pseudo-elements like
::beforeor::aftercannot be used inside the argument list. - Positive matching required:
:not()only filters elements that actually exist in the DOM; it cannot select elements that do not exist or style parent containers based on absent children (for child-dependent styling, consider the:has()relational pseudo-class).
Using the :not() pseudo-class streamlines CSS by
reducing code repetition and eliminating unnecessary selector overrides
across modern stylesheets.