🎯 CSS Specificity Calculator
By ToolNimba Web Dev Team · Updated 2026-06-19
- Token breakdown appears here.
Higher tuples win. Compare a first, then b, then c (like comparing the digits of a number). The universal selector (*) and combinators (>, +, ~, space) add nothing.
Specificity is the tie-breaker the browser uses when two CSS rules try to style the same element. Paste a selector here and this calculator parses it into the (a, b, c) score: a counts ID selectors, b counts classes, attributes and pseudo-classes, and c counts elements and pseudo-elements. You instantly see the weight, a token-by-token breakdown of what counted, and a plain explanation of how that score is compared against other rules.
What is the CSS Specificity Calculator?
Every CSS selector carries a specificity value, written as three numbers (a, b, c). The first number a is the count of ID selectors (#header). The second number b is the count of class selectors (.nav), attribute selectors ([type="text"]) and pseudo-classes (:hover). The third number c is the count of type selectors, that is element names (div, li), plus pseudo-elements (::before). The universal selector (*) and combinators (the descendant space, the child combinator, the adjacent sibling combinator and the general sibling combinator) add nothing to any column.
When two rules target the same property on the same element, the browser compares their specificity column by column, left to right, like comparing the digits of a number. It looks at a first: a higher a always wins, no matter what b and c are. Only when a is tied does b decide, and only when both a and b are tied does c decide. So one ID (1, 0, 0) beats any number of classes, and one class (0, 1, 0) beats any number of element names. If specificity is completely equal, the rule that appears later in the source order wins.
The functional pseudo-classes behave specially. The :not(), :is() and :has() functions do not add specificity themselves; instead they take the specificity of the most specific selector in their argument list. The :where() function is the opposite: it and everything inside it always count as zero, which makes it ideal for low-specificity defaults that are easy to override. Note that inline style attributes and the !important flag sit above this whole system and are not part of the (a, b, c) score at all.
When to use it
- Working out why a CSS rule you wrote is being ignored and another rule is winning instead.
- Comparing two competing selectors to see which one the browser will apply.
- Refactoring a bloated stylesheet to lower specificity so overrides become easier.
- Teaching or learning the cascade by experimenting with how each part of a selector scores.
- Auditing a design system to keep component styles at a predictable, low specificity using :where().
How to use the CSS Specificity Calculator
- Type or paste a CSS selector into the input box.
- Read the (a, b, c) tuple shown at the top: a = IDs, b = classes / attributes / pseudo-classes, c = elements / pseudo-elements.
- Check the "What counted" list to see exactly which token added to which column.
- Click an example chip to load a sample selector and watch the score change.
- Compare the tuple against another selector left to right (a, then b, then c) to see which rule wins.
Formula & method
Worked examples
Score the selector #nav ul li.active a:hover
- #nav is an ID selector, so a = 1
- .active is a class and :hover is a pseudo-class, so b = 2
- ul, li and a are element selectors, so c = 3
- The descendant spaces between them add nothing
- Combine the columns into the tuple (a, b, c)
Result: Specificity = (1, 2, 3)
Compare .btn.primary against #cta on the same button
- .btn.primary has no ID and two classes, so it scores (0, 2, 0)
- #cta has one ID and nothing else, so it scores (1, 0, 0)
- Compare column a first: 0 for the classes versus 1 for the ID
- A higher a wins outright, the b column never gets a vote
Result: #cta (1, 0, 0) wins over .btn.primary (0, 2, 0)
Score li:not(.first, #x) using the most specific argument rule
- li is an element selector, contributing c = 1
- :not() itself adds nothing, but it takes its most specific argument
- Inside :not() the arguments are .first (0, 1, 0) and #x (1, 0, 0)
- #x is the most specific, so :not() contributes (1, 0, 0)
- Add the element li to get the final score
Result: Specificity = (1, 0, 1)
How common selector parts contribute to the (a, b, c) score
| Selector part | Example | Column | Adds |
|---|---|---|---|
| ID selector | #header | a | 1 to a |
| Class selector | .menu | b | 1 to b |
| Attribute selector | [type="text"] | b | 1 to b |
| Pseudo-class | :hover | b | 1 to b |
| Type (element) selector | div | c | 1 to c |
| Pseudo-element | ::before | c | 1 to c |
| Universal selector | * | none | 0 |
| Combinators | > + ~ (space) | none | 0 |
Worked specificity scores for example selectors
| Selector | a | b | c | Tuple |
|---|---|---|---|---|
| * | 0 | 0 | 0 | (0, 0, 0) |
| li | 0 | 0 | 1 | (0, 0, 1) |
| ul li a | 0 | 0 | 3 | (0, 0, 3) |
| .active | 0 | 1 | 0 | (0, 1, 0) |
| a:hover | 0 | 1 | 1 | (0, 1, 1) |
| input[type="text"] | 0 | 1 | 1 | (0, 1, 1) |
| #nav ul li.active a:hover | 1 | 2 | 3 | (1, 2, 3) |
| p::first-line | 0 | 0 | 2 | (0, 0, 2) |
Common mistakes to avoid
- Thinking more selectors always means higher specificity. It is the columns that matter, not the total length. A single ID at (1, 0, 0) beats a long chain of ten classes at (0, 10, 0), because column a is compared before column b.
- Treating the tuple as a single base-10 number. Specificity is compared per column, not added into one figure. Eleven classes do not roll over into an ID. (0, 11, 0) is still beaten by (1, 0, 0), even though 11 looks bigger than 1.
- Forgetting that !important and inline styles sit outside the score. The (a, b, c) calculation only ranks normal selectors. An inline style attribute outranks them all, and an !important declaration outranks everything except another !important, so neither shows up in the tuple.
- Assuming :not() and :is() add to the score. These functional pseudo-classes contribute nothing on their own. They simply borrow the specificity of the most specific selector inside their brackets, which is easy to miss.
- Counting the universal selector or combinators. The * selector and the >, +, ~ and descendant (space) combinators never change specificity. Only the simple selectors they join together are counted.
Glossary
- Specificity
- The weight a browser assigns to a selector, written (a, b, c), used to decide which rule wins when several target the same element.
- Selector
- The pattern before a CSS rule that chooses which elements the declarations apply to, for example #nav ul li.active.
- Cascade
- The set of rules (origin, importance, specificity, source order) the browser follows to resolve conflicting declarations.
- Pseudo-class
- A keyword starting with one colon, like :hover or :first-child, that targets an element in a particular state. Counts toward b.
- Pseudo-element
- A keyword starting with two colons, like ::before or ::first-line, that styles a part of an element. Counts toward c.
- Combinator
- A character that relates two selectors, such as the descendant space, child >, adjacent sibling + or general sibling ~. Adds no specificity.
Frequently asked questions
What is CSS specificity?
Specificity is the weighting system browsers use to decide which CSS rule applies when more than one targets the same element and property. It is expressed as three numbers (a, b, c) counting IDs, then classes / attributes / pseudo-classes, then elements / pseudo-elements. The higher value, compared column by column, wins.
How is the (a, b, c) specificity score calculated?
Count the ID selectors for a, the class, attribute and pseudo-class selectors for b, and the type (element) selectors and pseudo-elements for c. The universal selector and combinators add nothing. This calculator parses your selector and reports each column automatically.
Which selector wins if two rules conflict?
Compare the tuples column by column from left to right. Whichever has the larger a wins; if a ties, the larger b wins; if a and b tie, the larger c wins. If all three are equal, the rule written later in the source order wins.
Does !important affect specificity?
No. The !important flag is not part of the (a, b, c) score. It sits above normal specificity in the cascade: an !important declaration beats any normal declaration regardless of selector weight, and only another !important (or a more specific one in certain origins) can override it.
How do :not(), :is() and :has() count?
These functional pseudo-classes add nothing themselves. They take on the specificity of the most specific selector inside their argument list. So :not(#id) contributes (1, 0, 0), while :is(.a, div) contributes (0, 1, 0) because the class is more specific than the element.
Why does my class rule lose to an ID rule even with several classes?
Because column a (IDs) is always compared before column b (classes). A single ID scores (1, 0, 0), which beats any number of classes such as (0, 5, 0). To win, you need either a higher a value or to reduce the other rule below an ID.