Overview
When two rules in the same origin and cascade layer set the same property on one element, the selector with the higher specificity wins. Check specificity before reaching for !important, which only starts an escalation war. Flat, class-based selectors avoid most conflicts.
Rules
- Weight is a three-column tuple compared left to right, not summed: IDs (A), then classes, attribute selectors, and pseudo-classes (B), then type selectors and pseudo-elements (C).
(0,1,0)beats(0,0,10). - Inline
styleoutranks all selectors.*, combinators, and:where()add nothing. :is(),:not(), and:has()take the specificity of their most specific argument; nesting&behaves like:is()of the parent selector. Group with:where()to keep a default easy to override.- Order third-party CSS with cascade layers instead of escalating selectors (cascade).
.card { color: blue; } /* (0,1,0) */
.card p { color: red; } /* (0,1,1) wins over .card */
#sidebar { color: green; } /* (1,0,0) beats both */A library’s .btn-primary (0,1,0) loses to a page rule .nav .btn-primary (0,2,0). Lower the page selector, or define the library default as :where(.btn-primary).
Related
- cascade: specificity is one step of the cascade.
- custom-property: tokens carry no selector weight.
- has-selector: weighted by its argument.
- css-cascade-layers: ordering without specificity.
- css-selectors: selector weights.