# Specificity: Scoring a Selector

Specificity is the score the browser gives every selector, in three columns, and comparing two scores column by column tells you which rule wins before you refresh.

Apprentice · CSS · Updated November 1, 2026

## After this lesson you can

- Score a selector's specificity in three columns, such as (0, 1, 1), and compare two scores column by column
- Fix a style that loses on specificity by changing a selector, and explain why ids and inline styles are hard to beat

## Key takeaways

- A selector's specificity is three counts, in order: ids; classes, attributes and pseudo-classes; types. So .product .price scores (0, 2, 0).
- Compare two scores column by column from the left. The first column that differs decides, so one id beats any number of classes.
- An inline style beats every selector, and an id is hard to beat. Style with classes, and keep your scores low and alike.
- In Chrome or Edge, hover over a selector in the Styles pane to see its score.

Spoke & Chain wants its prices green, so you write `.price { color: #2a9d8f; }`. The rule is right there in the file, it's spelled correctly, it even comes last, and the prices stay gray. Somewhere above it is a rule with a more precise selector, and precision beats position. Specificity is how the browser measures that precision, and once you can score a selector yourself, you can tell which rule will win before you save. You'll use it every time you add a style to a page someone else built.

## A score in three columns

Think of a medal table at the Olympics. Countries are ranked by gold medals first. Silver medals only count when two countries have the same number of golds, and bronze only when the silvers tie too. One gold beats any number of silvers.

A selector's **specificity** is a medal count in three columns:

| Column | Counts | Example |
|---|---|---|
| First (gold) | ids | `#featured` |
| Second (silver) | classes, attributes and pseudo-classes | `.price`, `[type="submit"]`, `:hover` |
| Third (bronze) | types (element names) | `p`, `span`, `h2` |

The score is written in brackets, such as (0, 1, 1), and read "zero, one, one". Working it out is called a **specificity calculation**:

```css
p.price {
  color: #2a9d8f;
}
```

`p.price` means "a `<p>` with the class `price`": no ids, one class, one type, so it scores (0, 1, 1).

Two selectors in the middle column are new here: an **attribute selector** such as `[type="submit"]` picks elements by an attribute, and a **pseudo-class** such as `:hover` (read "colon hover") picks them by their state, here "the mouse is over it". The next chapter, *Selectors in Depth*, teaches both. For scoring, they count like classes.

## Scoring real selectors

A space between two selectors means "inside": `.product .price` reads "a price inside a product". (*Combinators: Descendant, Child and Sibling* covers this and its relatives.) Each part of a selector adds to its own column:

| Selector | Ids | Classes, attributes, pseudo-classes | Types | Score |
|---|---|---|---|---|
| `span` | 0 | 0 | 1 | (0, 0, 1) |
| `.price` | 0 | 1 | 0 | (0, 1, 0) |
| `.product .price` | 0 | 2 | 0 | (0, 2, 0) |
| `a.button:hover` | 0 | 2 | 1 | (0, 2, 1) |
| `#featured` | 1 | 0 | 0 | (1, 0, 0) |
| `#featured .product span` | 1 | 1 | 1 | (1, 1, 1) |
| `*` | 0 | 0 | 0 | (0, 0, 0) |

The universal selector `*` adds nothing at all. And a selector list such as `h2, h3` isn't one selector: each selector in the list has its own score.

## Comparing two scores

Compare from the left, one column at a time, like the medal table. The first column where the scores differ decides, and the columns after it don't matter:

```html
<section id="featured">
  <div class="product">
    <span class="price">$649</span>
  </div>
</section>
```

```css
#featured .product span {
  color: #6c757d;
}

.product .price {
  color: #2a9d8f;
}
```

`#featured .product span` scores (1, 1, 1) and `.product .price` scores (0, 2, 0). The first column already differs, 1 against 0, so the id rule wins and the price is gray, `#6c757d`. Two classes don't add up to an id, and neither would eleven: (0, 11, 0) still loses to (1, 0, 0), because a column never carries over into the next one.

When every column ties, specificity can't decide, and the cascade moves on to source order: the later rule wins.

**Try it.** Score these before reading on: `h2`, `.sale-banner h2`, `#sale h2`. Then put all three rules on one heading, with a different color each, in the opposite order. Does the result match your scores?

## Inline styles and ids: the heavyweights

An **inline style** is a declaration written on the element itself, in its `style` attribute:

```html
<h2 class="sale-title" style="color: #264653;">Spring Sale: 20% off helmets</h2>
```

It isn't scored with the selectors at all: it beats every selector in every stylesheet, whatever their scores. Some guides show it as a fourth column in front, (1, 0, 0, 0). Either way, the only thing that beats it from a stylesheet is `!important`. The fix is to move the style out of the HTML into the stylesheet, where other rules can compete with it fairly.

Ids are the next heaviest. One id outscores any number of classes, so a rule with an id is beaten only by another id, an inline style or `!important` (or, as *Cascade Layers with @layer* shows later, by a rule in a stronger layer). That's how the arms race from *The Cascade: How the Browser Picks a Winner* begins. Many teams follow a simple habit:

- **Style with classes.** Their scores stay low and alike, so source order settles most ties, and you can see the order in the file.
- **Keep ids** for links to a part of the page (`href="#book"`) and for JavaScript.
- **Keep selectors short.** `.price` is easier to beat, and to reuse, than `#featured .product span.price`.

## See the score in the developer tools

In Chrome and Edge, inspect an element and hover over a selector in the **Styles** pane. A small box shows its score:

```text
Specificity: (1,1,1)
```

That's the hover box for `#featured .product span`. Hover over the winning selector and the losing one, and compare their columns from the left: the first difference is why the winner won.

![The Styles pane with the mouse over the selector #featured .product span, and a box above it that reads Specificity (1,1,1)](https://www.ask-codey.com/lessons/TODO)

## Fixing a style that loses on specificity

When your rule loses this round, you have three honest fixes. Here are the three for the gray price, from the best:

```css
/* 1. Make the winner less precise: it was meant for the brand name only */
.brand {
  color: #6c757d;
}

/* 2. Or make yours a little more precise than the winner */
#featured .product .price {
  color: #2a9d8f;
}
```

1. **Lower the winner.** Often the too-strong rule was aimed at something else. Here `#featured .product span` was meant for the gray brand name, `<span class="brand">`, and caught the price too. Rewriting it as `.brand`, (0, 1, 0), fixes the cause.
2. **Raise yours, a little.** `#featured .product .price` scores (1, 2, 0) and beats (1, 1, 1). It works, but your rule is now hard to beat too.
3. **Reorder, for a tie.** If the scores are equal, put your rule after the other one.

`!important` isn't on the list: it hides the cause and makes the next fix harder.

**Try it.** In the developer tools, find a crossed-out declaration on any page and hover over both selectors. Which column decided? Write down the fix you'd make.

## Check yourself

2 questions to try on the lesson page.

## So what

Specificity turns "CSS is random" into arithmetic you can do in your head. Score the two selectors, compare from the left, and you know which rule wins and how to change that, without reaching for `!important`.

## Key terms

- [Specificity](https://www.ask-codey.com/glossary/specificity)
- [Specificity calculation](https://www.ask-codey.com/glossary/specificity-calculation)
- [Inline style](https://www.ask-codey.com/glossary/inline-style)

## Cheat sheets

- [Specificity: Scoring a Selector](https://www.ask-codey.com/cheat-sheets/css-specificity-cheat-sheet)

## Related

- [The Cascade: How the Browser Picks a Winner](https://www.ask-codey.com/lessons/css-cascade)
- [Type, Class and ID Selectors](https://www.ask-codey.com/lessons/css-selectors-type-class-id)
- [Combinators: Descendant, Child and Sibling](https://www.ask-codey.com/lessons/css-combinators)

Source: https://www.ask-codey.com/lessons/css-specificity
