Specificity in CSS decides which selector wins when multiple rules target the same element and property. It is one of the most important CSS concepts because many styling bugs are not caused by missing CSS. They are caused by CSS being overridden by a more specific rule.
Specificity works together with the cascade, source order, importance, layers, inheritance, and browser defaults. Understanding specificity helps you write CSS that is predictable instead of fighting it with random !important declarations.
What Specificity Measures
Specificity measures selector weight. Inline styles are strongest in normal specificity. IDs are stronger than classes. Classes, attributes, and pseudo classes are stronger than element selectors. Universal selectors have no specificity.
| Selector Type | Example | Weight Idea |
|---|---|---|
| Inline style | style=”” | highest normal specificity |
| ID | #header | very strong |
| Class | .card | medium |
| Attribute | [type=”text”] | medium |
| Pseudo class | :hover | medium |
| Element | button | low |
Specificity Format
Specificity is often explained as columns: inline styles, IDs, classes and pseudo classes, then elements and pseudo elements. The exact notation may vary, but the comparison idea is the same.
#main .card button {
color: blue;
}
.card button {
color: red;
}
The first selector wins because it includes an ID. Source order does not matter unless specificity is equal.
Element Selectors
Element selectors have low specificity. They are useful for base styles and defaults.
button {
font: inherit;
cursor: pointer;
}
This creates a baseline for all buttons. Component classes can override it easily because classes have higher specificity.
Class Selectors
Class selectors are the workhorse of maintainable CSS. They are specific enough for components but not so strong that overrides become painful.
.button {
background: #2563eb;
color: white;
}
Most component styling should use classes. This keeps selectors reusable and predictable.
ID Selectors
ID selectors are very specific. They can be useful for fragment links and unique document regions, but they are often too strong for everyday styling.
#site-header {
position: sticky;
top: 0;
}
Using IDs heavily can make CSS hard to override. Prefer classes for component styles unless the ID is truly needed.
Inline Styles
Inline styles have very high specificity. They often come from JavaScript, page builders, or component libraries.
<div style="color: red;">Text</div>
Normal stylesheet rules usually cannot override inline styles unless !important is used. This is one reason inline styling should be used carefully.
Pseudo Classes and Pseudo Elements
Pseudo classes such as :hover, :focus, and :nth-child() count like classes. Pseudo elements such as ::before and ::after count like element selectors.
.button:hover {
background: #1d4ed8;
}
.button::before {
content: "";
}
This distinction matters when debugging why a state style or generated element style is being overridden.
:is(), :not() and :has()
The specificity of :is(), :not(), and :has() is based on the most specific selector inside them.
:is(.card, #featured) h2 {
color: #111827;
}
Because #featured is inside :is(), the selector can become very specific. Be careful when mixing IDs into these pseudo classes.
:where()
The :where() pseudo class always has zero specificity, no matter what is inside it. This is useful for reset styles and defaults that should be easy to override.
:where(article h2, article h3) {
margin-block-start: 2rem;
}
Even though the selector looks detailed, it is intentionally easy to override. This makes :where() useful in modern CSS architecture.
Source Order with Equal Specificity
If two selectors have equal specificity and affect the same property, the later rule wins.
.button {
background: blue;
}
.button {
background: green;
}
The button becomes green because the second rule appears later and has equal specificity.
!important
The !important flag overrides normal specificity rules within the same origin and layer rules. It should be used sparingly because it makes future overrides harder.
.button {
background: red !important;
}
Use !important only when necessary, such as utility classes, third-party overrides, or emergency fixes. Do not use it as a normal debugging habit.
Specificity Wars
Specificity wars happen when selectors keep becoming longer and stronger to override earlier rules. This leads to CSS that is hard to maintain.
body .page .content .card .button.primary {
background: red;
}
This selector is fragile. A simpler class or better cascade structure would be easier to work with.
Keeping Specificity Low
Low specificity makes CSS easier to override. Use classes, avoid unnecessary IDs, avoid long descendant chains, and use :where() for broad defaults.
- Prefer class selectors for components.
- Avoid styling deeply through page structure.
- Avoid IDs for reusable styling.
- Use :where() for low-specificity defaults.
- Use cascade layers when a project needs clear style ordering.
- Reserve !important for rare cases.
Debugging Specificity
Browser developer tools show which rule wins and which rules are crossed out. When a style is not applying, inspect the element and compare specificity, source order, layers, and whether !important is involved.
Do not guess. The computed styles panel usually shows the exact winning declaration.
Cascade Layers and Specificity
Cascade layers can reduce specificity fights by giving groups of CSS a clear order. A low-specificity rule in a later layer can beat a higher-specificity rule in an earlier layer, depending on cascade layer order.
@layer reset, base, components, utilities;
@layer base {
button {
font: inherit;
}
}
@layer utilities {
.text-red {
color: red;
}
}
Layers are useful in design systems because resets, defaults, components, and utilities can be organized intentionally instead of relying only on selector strength.
Specificity in Component CSS
Component CSS should usually keep specificity low and predictable. A class such as .card-title is easier to override than a long chain such as .page .sidebar .card h2.
.card-title {
font-size: 1.5rem;
}
.featured-card .card-title {
color: #2563eb;
}
The second selector is slightly more specific because it describes a clear component variant. This is better than depending on deep page structure.
Specificity and Utility Classes
Utility classes often rely on predictable source order or cascade layers. They should be easy to apply without needing very specific selectors.
.mt-0 {
margin-top: 0;
}
.text-center {
text-align: center;
}
Some utility systems use !important deliberately, but that should be a documented architecture choice, not a random habit.
Overriding Third Party CSS
Third-party plugins, themes, and page builders may ship strong selectors or inline styles. Before overriding them, inspect the actual winning rule. Then choose the smallest override that works.
If you immediately add IDs and !important, you may fix one issue while making future styling harder. A wrapper class, later layer, or better enqueue order may solve the problem more cleanly.
Specificity Checklist
- Start with simple class selectors.
- Avoid IDs for normal reusable styling.
- Use :where() for defaults that should be easy to override.
- Use cascade layers for large style systems.
- Inspect the winning rule before increasing specificity.
- Use !important only when the architecture calls for it.
Specificity Calculation Examples
The easiest way to learn specificity is to compare selectors directly. Count IDs first, then classes, attributes, and pseudo classes, then elements and pseudo elements.
| Selector | Why It Wins or Loses |
|---|---|
| .card h2 | one class plus one element |
| .featured .card h2 | two classes plus one element |
| #main .card h2 | one ID beats class-only selectors |
| :where(.card h2) | zero specificity from :where() |
The selector with an ID usually beats several class selectors. The selector inside :where() is intentionally weak, even if it looks detailed.
Specificity and Inheritance
Inherited styles are weaker than directly applied styles. If a parent sets color, a direct rule on the child can override it easily.
.card {
color: #6b7280;
}
.card-title {
color: #111827;
}
The title color wins because it is directly applied to the title. Specificity is only part of the story; whether a property is inherited also matters.
Specificity and Browser Defaults
Browser default styles have low priority compared with author styles. A simple rule like button can override many browser defaults, but form controls may still have platform-specific behavior.
When styling forms, inspect computed styles instead of assuming every visual detail comes from your CSS.
Avoiding Specificity Debt
Specificity debt builds up when every fix uses a stronger selector than the last one. Eventually the stylesheet becomes difficult to change because small design updates require very heavy selectors.
The solution is not more force. The solution is better structure: layers, components, low-specificity defaults, and predictable utility classes.
Practical Override Strategy
When a rule does not apply, do not immediately write a stronger selector. First inspect the winner. If the winning rule comes from source order, move the override later. If it comes from a layer, place the override in the correct layer. If it comes from an ID or inline style, decide whether the source CSS should be changed instead.
.button {
background: #2563eb;
}
.button.is-danger {
background: #dc2626;
}
This override is clear because it describes a component state. It is better than reaching through the whole page structure with a long descendant selector.
Specificity and Naming
Clear class names reduce the need for complex selectors. If a component has a meaningful class for each part, CSS can stay flat and readable.
.pricing-card {}
.pricing-card-title {}
.pricing-card-price {}
This structure is easier to override than styling every element through .pricing-section div:nth-child() chains. Good naming is a specificity tool.
Specificity Checklist
- Use the simplest selector that communicates intent.
- Prefer component classes over DOM-depth selectors.
- Use variants like .is-active or .is-danger clearly.
- Use DevTools before increasing selector strength.
- Keep defaults easy to override.
- Document any intentional !important usage.
Common Specificity Mistakes
- Using IDs for normal component styling.
- Making selectors longer instead of improving structure.
- Using !important as the first fix.
- Forgetting source order when specificity is equal.
- Not understanding :where() has zero specificity.
- Mixing third-party CSS without a clear override strategy.
Specificity in CSS FAQ
What is specificity in CSS?
Specificity is the selector weight used to decide which CSS rule wins when multiple rules target the same property.
Are IDs more specific than classes?
Yes. ID selectors have much higher specificity than class selectors.
Does source order matter?
Yes, when competing rules have equal specificity and the same importance.
Does :where() add specificity?
No. :where() always has zero specificity.
Continue learning CSS in order
Follow the topic sequence with the previous and next lesson.