Reference guide · html-css-js · Published 2026-08-15 · 3 min read

CSS specificity: which rule wins

CSS specificity explained: inline styles, IDs, classes and elements, the cascade, and the cost of using !important.

What specificity means

When two CSS rules target the same property of the same element, the browser has to pick one. It picks the selector with the higher specificity. Specificity is a four-part score, counted in the order: inline styles, IDs, classes and attributes, element and pseudo-element types.

Selector kindWeightExample
Inline style attributeHigheststyle="color: red"
ID selector1,0,0#nav
Class, attribute, pseudo-class0,1,0.card, [type="email"], :hover
Element, pseudo-element0,0,1div, ::before
Universal, combinatorsNo weight*, >, +

A selector with one ID beats any number of classes. That is the part people misjudge: .btn never overrides #submit-btn even with hundreds of rules behind it.

The worked example

Compare these rules on the same <button id="save" class="btn primary">.

button { color: gray; }              /* 0,0,1 */
.btn { color: blue; }                /* 0,1,0 */
.btn.primary { color: green; }       /* 0,2,0 */
#save { color: red; }                /* 1,0,0 */

The winning color is red. The ID rule scores 1,0,0, and nothing else in the list touches an ID. Two classes together score 0,2,0, which beats a single class but loses to the ID. If you added style="color: purple" to the markup, the inline style would beat the ID rule.

Where the cascade matters

Specificity is not the only deciding factor. Three more rules affect the outcome.

  1. Source order: when specificity ties, the rule declared later in the CSS wins.
  2. Inheritance: some properties inherit from the parent. A child rule beats the inherited value on its own element, and specificity decides between competing child rules.
  3. !important moves a declaration to its own lane: it beats normal rules from any specificity, and tie-breaks inside !important still follow specificity and source order. An inline !important beats a stylesheet !important.

Why !important is a trap

!important works exactly once. The next developer hits the same conflict and adds another !important. The stylesheet fills with them, specificity stops holding any meaning, and every new component inherits the mess. There are two places where it is normally fine: overriding user agent styles you cannot reach otherwise, and the few cases where a third-party script writes inline styles you must beat. Everywhere else, treat it as a code smell.

/* Rethink these */
.note { color: #111 !important; }

/* Prefer fixing the selector that is too strong */
.alert .note { color: #111; }

Debugging with devtools

When a style is not applying, the computed styles panel in DevTools is the evidence. Select the element, open the Styles tab, and the browser lists every matching rule with its origin, specificity, and a strike-through on the declarations that lost. If the property you expect is struck through, look for the rule that beat it further up the list. From there the fix is honest: either lower the specificity of the winning selector, raise yours, or remove the inline style that is sitting on the element. Renaming #nav to .nav alone often removes a whole class of conflicts, which is the direction the CSS versus inline styles comparison takes. The remaining conflicts usually reset to the box model, where margins and padding fail for separate reasons.

Need a website built, fixed, optimised, migrated or replaced?

This technical resource is written by CSMBAC, a small design and development studio. If you would rather hand the problem to a professional, the website service page explains how we build enquiry-ready websites.

Explore website services