Why is my CSS not applying?
A more specific selector elsewhere is winning. Count specificity as (inline, IDs, classes/attributes/pseudo-classes, elements) and compare left to right — the first difference decides.
| Selector | Specificity |
|---|---|
p | 0,0,0,1 |
.card | 0,0,1,0 |
.card p | 0,0,1,1 |
.card.is-active | 0,0,2,0 |
#main .card | 0,1,1,0 |
style="…" | 1,0,0,0 |
Higher wins. When two selectors tie exactly, the one written later wins.
#Diagnose it in DevTools
Inspect the element and look at the Styles panel. Overridden declarations are shown with a strikethrough, and the rule that won is at the top. That tells you in two seconds what guessing takes twenty minutes to find.
#Common causes that are not specificity
- A typo in the class name, or the class not actually on the element.
- The stylesheet did not load — check the Network tab for a 404.
- The property does not apply to that element.
widthdoes nothing on an inline element; give itdisplay: inline-blockorblock. - A shorthand later reset it.
background: redclearsbackground-image. - The value is invalid. One bad declaration is dropped silently; the rest of the rule still applies.
#Do not reach for !important
It wins, but it starts an arms race — the next override needs !important too, and now nothing can be adjusted normally. Instead:
Lower the specificity of the winning rule. #main .card almost never needs the ID.
Raise yours minimally. .card.card is a legitimate trick: repeating a class doubles its specificity without adding an ID.
Use :where() for zero-specificity defaults. Everything inside :where() counts as 0, which makes base styles trivially overridable:
:where(.prose) a { color: blue; } /* any single class beats this */#Layers make it explicit
@layer base, components, utilities;Later layers beat earlier ones regardless of specificity. This is the modern answer to the whole problem.