CSS specificity is a three-part comparison—ID, CLASS, TYPE—that helps the browser choose between declarations that otherwise reach the same element. It is not a decimal score: compare the ID count first, then the class/attribute/pseudo-class count, then the type/pseudo-element count. But specificity is not the first cascade decision; origin, importance and cascade layer can decide the winner before the selector is compared.
How to calculate CSS specificity
Write a selector’s specificity as A-B-C, where A counts ID selectors, B counts class selectors, attribute selectors and most pseudo-classes, and C counts type selectors and pseudo-elements. Compare the three values from left to right. A larger value in an earlier column wins regardless of the later columns; for example, one ID outranks any number of classes or type selectors. This is a column-by-column comparison, not a base-10 number.
| Selector component | Column | Examples that count |
|---|---|---|
| ID selectors | A | #nav |
| Classes, attributes and most pseudo-classes | B | .item, [id="nav"], :hover |
| Type selectors and pseudo-elements | C | a, ::before |
Combinators such as a space, > or +, and the universal selector *, add no specificity. MDN’s specificity guide explains the counting rules and cascade context.
| Selector | Specificity | Why |
|---|---|---|
#nav .item a |
1-1-1 |
One ID, one class and one type selector |
.card:hover |
0-2-0 |
One class and one pseudo-class |
article p |
0-0-2 |
Two type selectors; the descendant combinator adds nothing |
[id="nav"] |
0-1-0 |
An attribute selector, not an ID selector |
That last distinction matters: #nav and [id="nav"] may match the same element, but their specificity differs.
#1 Best Overall
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
How :is(), :not(), :has() and :where() affect specificity
:is(), :not() and :has() do not add a fixed amount simply for appearing in a selector. Instead, the most specific selector in their argument list contributes. For instance, :is(.note, #urgent) contributes 1-0-0 from its most specific argument, even when the matched element corresponds to .note.
:where() and everything inside its argument list contribute 0-0-0. It is useful for writing selectors that target a specific structure without making later overrides harder. CSS nesting follows a related rule: the highest specificity in the associated selector list is used.
Rank #2
The W3C Selectors Level 4 specificity rules define these functional-selector and comparison behaviors.
Why a more specific CSS rule may not win
Specificity is only one stage of the cascade. Before comparing selector weights, the browser resolves origin and importance, then cascade-layer precedence. Scoping proximity is considered after specificity, and source order settles a remaining tie. MDN’s cascade overview describes this sequence. Therefore, a selector with more IDs does not automatically beat a declaration that has already won at an earlier cascade stage.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Rank #3
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
- Origin and importance: Check whether the declarations come from the same origin and whether either is marked
!important. Specificity cannot reverse a result already determined here. - Layer: For normal declarations, a later cascade layer takes precedence over an earlier one. For important declarations, the layer order is reversed: an important declaration in an earlier layer takes precedence over one in a later layer. The W3C Cascade Level 5 layer-order rules specify this behavior.
- Specificity: Only compare the ID–CLASS–TYPE tuple after the earlier cascade choices permit it to decide.
- Scoping proximity: If specificity ties, scoped rules are compared by how close their scope is to the matched element.
- Source order: When the relevant earlier criteria tie, the declaration appearing later wins.
A practical method for debugging an override
- Identify the declarations that actually match. In the browser’s developer tools, inspect the element and locate the competing rules for the property in question.
- Compare origin and importance. Check whether the rules differ in origin or whether one uses
!important. If one wins at this stage, changing selector specificity will not fix the conflict. - Compare cascade layers. Note each declaration’s layer. For normal declarations, later layers win; for important declarations, earlier layers win. Unlayered styles also have defined precedence relative to layered styles, so verify the actual cascade context rather than assuming selector weight is decisive.
- Calculate each selector’s tuple. Count IDs, then classes/attributes/most pseudo-classes, then types/pseudo-elements. Ignore combinators and
*; apply the special rules for functional pseudo-classes and nesting. - Check scope and source order if the tuples tie. Consider which scoped rule is closer to the element. If proximity also ties, the later declaration wins.
- Change the cause, not just the selector weight. Put styles into intentional layers, move a rule to the appropriate layer, or reduce unnecessary specificity. Avoid adding IDs or repeating selectors unless that specificity is deliberate and maintainable.
Use cascade layers to make overrides easier
Layers let a stylesheet express broad precedence without escalating selector weight. For example, place third-party or base styles in an earlier layer and application overrides in a later layer. Within the applicable precedence rules, the later layer can then provide the intended normal declaration without a selector arms race. Keep important declarations in mind: their layer order is reversed, so they should be used sparingly and deliberately.
For reusable component styles, :where() can keep a structural selector at zero specificity, leaving ordinary application rules room to override it. This is often more robust than encoding priority through long chains of classes or IDs.
Quick Recap
Best Value
Rank #4
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

