HTML, CSS & the Browser

CSS Specificity

Definition

Every selector gets a score in three parts, usually written as three numbers. Ids count in the first: #header scores 1-0-0. Classes, attribute selectors and pseudo-classes count in the second, so .card, [type="email"] and :hover each score 0-1-0. Element names and pseudo-elements count in the third: p and ::before score 0-0-1. The parts are compared left to right and do not carry, so a single id at 1-0-0 beats eleven classes at 0-11-0 outright. A selector like nav .menu a.active scores 0-2-1. The universal selector and :where() add nothing, an inline style outranks any selector, and !important sits above the lot.

Why It Matters

This is the mechanism behind the most common frustration in CSS: you write a rule that plainly describes the element, reload, and nothing changes. Nine times in ten the rule is correct and simply outranked — something earlier in the file targets the same element through an id or a longer chain and scores higher, so source order never gets a say. Knowing the weighting turns a guessing game into arithmetic: compare the two selectors, see that #sidebar p at 1-0-1 beats .note at 0-1-0, and the fix is obvious rather than accidental. It also tells you when your own stylesheet is drifting, because the need to keep escalating is the symptom.

How It Works

For each property on each element the browser gathers every declaration that matches, then sorts them: first by origin and importance, then by specificity, and only at the end by source order. Inline styles are handled as a separate, higher level than any selector. A declaration marked !important jumps above all normal declarations, and competing important declarations are compared by specificity among themselves. The practical implication is that !important is a symptom, not a fix — it wins today, but it removes the normal ordering rules for that property, so the next person who needs to override it has no move left except another !important. Developer tools show the losing rules struck through in the styles panel, which is the fastest way to see exactly what beat you.

Real-World Example

A microsite at spring-launch.99helpers.site has a notice box that stays grey however many times the colour is changed. The generated stylesheet contains #main .notice { background: #eee; } at 1-1-0, while the hand-added .notice-warning { background: #fde68a; } scores 0-1-0 and loses regardless of where it sits. Rewriting the rule as #main .notice-warning brings it to 1-1-0 and, being later, it wins cleanly — with no !important anywhere and nothing else in the page affected.

Common Mistakes

  • Reaching for !important the first time a rule does not apply — it wins the round and loses the war, because every later override now has to be important too
  • Assuming the rule further down the file always wins — source order only breaks ties, and a single id beats any number of classes before order is even considered
  • Raising specificity by pasting in a longer ancestor chain — it works once, then sets a floor everything else has to clear, and the stylesheet ratchets upward

Related Terms

Put a file online in seconds

Drop in a document, an image, a page or a whole static website and share the link — free, with no build step and no server to set up.

Host a file free →