CSS Specificity for the :not Pseudo-Class
Understanding how CSS specificity works within the
:not() negation pseudo-class is essential for writing
predictable and maintainable stylesheets. While the :not()
pseudo-class itself contributes no specificity to a selector, it adopts
the specificity of the most specific selector present within its
argument list. This article explains how CSS calculates specificity for
negation lists like :not(.class1, .class2) and details the
implications this behavior has on styling rules.
The Most Specific Argument Rule
In CSS Selectors Level 4, functional pseudo-classes such as
:not(), :is(), and :has() accept
comma-separated selector lists. When determining the specificity of the
pseudo-class, the browser does not count the pseudo-class name itself
(its base specificity is 0-0-0). Instead, the browser
analyzes every selector inside the parentheses and assigns the entire
pseudo-class the specificity of the single argument with the highest
specificity weight.
Specificity Breakdown
of :not(.class1, .class2)
When evaluating :not(.class1, .class2), the calculation
proceeds as follows:
- Evaluate the first argument:
.class1is a class selector with a specificity of0-1-0(0 ID selectors, 1 class/attribute/pseudo-class selector, 0 type/element selectors). - Evaluate the second argument:
.class2is also a class selector with a specificity of0-1-0. - Determine the highest specificity: Between
0-1-0and0-1-0, the highest value is0-1-0. - Apply to the selector: The entire
:not(.class1, .class2)expression receives a specificity of0-1-0.
If you attach this pseudo-class to an element, such as
button:not(.class1, .class2), the element selector
(button, which has a weight of 0-0-1) is added
to the pseudo-class specificity (0-1-0), resulting in a
total specificity of 0-1-1.
Mixed Specificity Within
:not()
The calculation becomes particularly important when arguments inside
the list carry different weights. Consider the selector
:not(.class1, #unique-id):
.class1carries a weight of0-1-0.#unique-idcarries a weight of1-0-0.
Because #unique-id has the highest specificity in the
list, the entire :not(.class1, #unique-id) selector takes
on a specificity of 1-0-0. Even if a target element fails
to match .class1 and has nothing to do with
#unique-id, any rule using this selector will still carry
the heavy specificity of an ID selector.
Practical Takeaway
For :not(.class1, .class2), the specificity is always
equal to a single class (0-1-0) because both arguments
share the same weight. When writing selector lists inside
:not(), keep arguments at similar specificity levels to
avoid accidentally inflating the selector's weight and creating
difficult-to-override rules elsewhere in your CSS.