Skip to content
Commitpedia
Log in Join & edit

CSS selectors and specificity reference

The selectors you will use every day, how the browser decides which rule wins when several match, and practical ways to keep specificity low and predictable.

Not checked by a trusted editor yet Last edited Outdated?

Edit history of CSS selectors and specificity reference: 1 recorded edit
Edit history · 1 edit
Type
Article
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Reading
2 min

A selector picks which elements a CSS rule applies to. When several rules set the same property on the same element, the cascade decides which one wins, and specificity is the part of that decision developers bump into most often.

Everyday selectors

  • p: type selector, every <p>.
  • .card: class selector.
  • #main: ID selector.
  • [type="email"]: attribute selector. Also [href^="https"] (starts with), [href$=".pdf"] (ends with), [class*="btn"] (contains).
  • *: universal selector.
  • a:hover, input:focus-visible, li:first-child, li:nth-child(2n), input:checked, button:disabled: pseudo-classes, matching a state or position.
  • p::first-line, .note::before, input::placeholder: pseudo-elements, styling a part of an element.

Combinators

  • nav a: descendant, any a inside nav.
  • ul > li: direct child only.
  • h2 + p: the paragraph immediately after an h2.
  • h2 ~ p: every later sibling paragraph.

Logical pseudo-classes

  • :is(h1, h2, h3) a: matches any of the list, shortening repetitive selectors.
  • :where(...): same as :is() but with zero specificity, ideal for defaults that are easy to override.
  • :not(.active): excludes matches.
  • .card:has(img): matches a card that contains an image. Supported in all current major browsers.

How specificity is calculated

Specificity is compared as three numbers, written (A, B, C):

  • A: number of ID selectors.
  • B: classes, attribute selectors, and pseudo-classes.
  • C: type selectors and pseudo-elements.

Compare A first; only if it ties, compare B, then C. The universal selector and combinators add nothing. :is(), :not(), and :has() take the specificity of their most specific argument, and :where() always counts as zero.

p                      /* (0, 0, 1) */
.card p                /* (0, 1, 1) */
nav a:hover            /* (0, 1, 2) */
#main .card            /* (1, 1, 0) */
:where(#main) .card    /* (0, 1, 0) */
.btn.btn-primary       /* (0, 2, 0) */

Because the comparison goes column by column, one ID beats any number of classes: #main wins over .a.b.c.d.e.f.

The rest of the cascade

Specificity is not the first check. In simplified order, the browser considers:

  1. Origin and importance: !important declarations beat normal ones.
  2. Cascade layers: for normal declarations, styles in a later @layer beat earlier layers, and unlayered styles beat all layers, regardless of specificity.
  3. Specificity.
  4. Source order: if everything else ties, the rule that appears last wins.

Inline style="..." attributes beat any selector unless the other rule uses !important.

Keeping it manageable

  • Style with classes, not IDs. Keep most selectors at one or two classes.
  • Avoid long descendant chains like .page .sidebar ul li a; they are fragile and hard to override.
  • Put resets and library defaults inside :where() or a low @layer so your own styles win without a fight.
  • Treat !important as a last resort, mostly for utility classes that must always apply.
  • In DevTools, the Styles panel lists matching rules in winning order and crosses out overridden declarations. Hovering a selector shows its specificity in Chromium-based browsers.

Did this work for you?

No votes yet. Be the first.

If it did not work, the report form below tells the editors what went wrong.

See also

  • 0082 HTTP status codes: the common ones and what to do A quick reference to the HTTP status codes you will meet most often, what each one means, and the first thing to… Beginner · Cheat sheet · Any system Article References · Status codes 15 Oct 2026

Repos in the wild

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Commitpedia +3,127 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?