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 style outranks 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).