# How CSS Specificity Works and Is Calculated: The Complete (a,b,c,d) Guide

> Understand CSS specificity calculations using the (a,b,c,d) model. Learn how inline styles, IDs, classes, and types determine style precedence for conflict resolution.

- Repository: [H5BP/Front-end-Developer-Interview-Questions](https://github.com/h5bp/Front-end-Developer-Interview-Questions)
- Tags: tutorial
- Published: 2026-03-05

---

**CSS specificity is calculated using a four-component tuple (a, b, c, d) where inline styles (a) outrank ID selectors (b), which outrank class/attribute/pseudo-class selectors (c), which outrank type/pseudo-element selectors (d), with browsers comparing these values left-to-right to resolve conflicts and `!important` declarations overriding normal calculations.**

According to the h5bp/Front-end-Developer-Interview-Questions repository, understanding selector specificity is essential for front-end developers. The interview questions documented in [`src/questions/css-questions.md`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/questions/css-questions.md) examine exactly how browsers resolve conflicting style declarations when multiple selectors target the same element.

## The Specificity Calculation Model

The browser assigns every CSS selector a weight represented as a four-segment tuple **(a, b, c, d)**. Each segment counts a specific category of selector component, with higher-precedence categories completely outweighing lower ones regardless of quantity.

### Segment A: Inline Styles

The `a` component counts inline styles declared directly on an element via the `style` attribute. Each instance contributes 1 to the `a` value, producing a tuple of **(1,0,0,0)**.

- Example: `<p style="color: red;">` sets `a = 1`.

### Segment B: ID Selectors

The `b` component counts ID selectors such as `#header` or `#main`. Each ID contributes 1 to the `b` value, producing a base tuple of **(0,1,0,0)**.

- Example: `#intro { color: red; }` sets `b = 1`.

### Segment C: Class, Attribute, and Pseudo-Class Selectors

The `c` component counts class selectors (`.button`), attribute selectors (`[type="text"]`), and pseudo-classes (`:hover`, `:focus`, `:nth-child()`). Each contributes 1 to the `c` value.

- Example: `.active:hover` results in **(0,0,2,0)** (two c-segment selectors).

### Segment D: Type and Pseudo-Element Selectors

The `d` component counts HTML element selectors (`div`, `p`, `h1`) and pseudo-elements (`::before`, `::after`). Each contributes 1 to the `d` value.

- Example: `h1::before` results in **(0,0,0,2)** (one type + one pseudo-element).

## Selectors That Do Not Add Specificity Weight

As documented in [`src/questions/css-questions.md`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/questions/css-questions.md), several selector types contribute **zero** to the specificity calculation:

- **Universal selector** (`*`)
- **Combinators** (`>`, `+`, `~`, and the whitespace descendant combinator)
- **Negation pseudo-class** (`:not()`) — though selectors passed as arguments inside `:not()` do contribute their respective weights

## How Specificity Comparison Works

When multiple rules match the same element, the browser compares their **(a, b, c, d)** tuples from left to right:

1. The higher `a` value wins immediately.
2. If `a` is tied, the higher `b` value wins.
3. If `b` is tied, the higher `c` value wins.
4. If `c` is tied, the higher `d` value wins.

If all tuple values are identical, the declaration that appears **later** in the stylesheet wins due to source order precedence.

## The !important Exception

An `!important` declaration overrides normal specificity calculations entirely. However, if two conflicting declarations both use `!important`, the browser falls back to the standard **(a, b, c, d)** comparison to determine which important declaration applies.

```css
/* Specificity: (0,0,0,1) */
a { color: purple; }

/* Specificity: (0,0,1,1) + !important */
a.special { color: teal !important; }

```

In this example from the source documentation, `a.special` wins due to `!important`, even if another rule had higher specificity but lacked the flag.

## Practical Specificity Examples

Consider the following markup and styles based on examples in [`src/questions/css-questions.md`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/questions/css-questions.md):

```html
<style>
  /* Specificity: (0,0,0,1) */
  p { color: blue; }

  /* Specificity: (0,0,1,0) */
  .highlight { color: green; }

  /* Specificity: (0,1,0,0) */
  #intro { color: red; }
</style>

<p id="intro" class="highlight" style="color: orange;">Demo</p>

```

The text renders **orange** because the inline style has specificity **(1,0,0,0)**, which outranks the ID selector **(0,1,0,0)**, regardless of the ID's high precedence relative to classes and elements.

## Summary

- CSS specificity uses a four-component tuple **(a, b, c, d)** to hierarchically weight inline styles, IDs, classes/attributes/pseudo-classes, and type/pseudo-elements respectively.
- **Universal selectors**, **combinators**, and the **`:not()`** pseudo-class itself contribute zero specificity.
- Browsers compare tuples **left-to-right**; the first non-tied higher value wins.
- When specificity values are equal, the **last declared** rule wins.
- **`!important`** declarations trump normal specificity, but specificity is recalculated normally when both competing declarations use the flag.

## Frequently Asked Questions

### What is the (a,b,c,d) specificity tuple?

The **(a,b,c,d)** tuple is a four-digit representation where **a** counts inline styles, **b** counts ID selectors, **c** counts class/attribute/pseudo-class selectors, and **d** counts type/pseudo-element selectors. The browser compares these values from left to right, with each position outweighing any combination of subsequent positions.

### Does the universal selector (*) affect specificity?

No. The universal selector (`*`) contributes zero to all four specificity components. Similarly, combinators like `>`, `+`, and `~` add no weight; only the selectors they connect contribute to the calculation, as specified in the h5bp interview questions.

### How does !important interact with specificity?

`!important` declarations exist outside normal specificity calculations and automatically override non-important declarations regardless of selector weight. However, if two declarations both include `!important`, the browser reverts to calculating specificity using the standard **(a,b,c,d)** rules to determine which important declaration applies.

### Can multiple class selectors beat a single ID selector?

No. Due to the left-to-right tuple comparison, even numerous class selectors (yielding a high `c` value) cannot overcome a single ID selector (which sets the `b` value). For example, **(0,1,0,0)** (one ID) wins over **(0,0,255,0)** (255 classes) because the `b` value is compared before the `c` value.