What the cascade decides
When several CSS declarations set the same property on the same element, the
cascade picks the winner. Before specificity or source order ever come into
play, the cascade first sorts declarations by their origin (who wrote them)
and importance (normal vs !important). Getting this order right explains
why a heavily-specific author rule can still lose to a humble user-agent default
marked !important.
How it works
The cascade compares declarations top to bottom through these tiers (highest priority first):
- Transitions
- User-agent
!important - User
!important - Author
!important - CSS animations
- Author normal
- User normal
- User-agent normal
The key insight is the !important reversal: for normal declarations the
order is author over user over user-agent, but for !important declarations it
flips to user-agent over user over author. This protects user and accessibility
overrides. Cascade layers (@layer) subdivide the author tiers, and only when
two declarations tie on all of the above does the engine fall through to
specificity and then source order.
Why !important reverses the order — the accessibility rationale
The reversal exists because CSS was designed to balance the interests of page
authors and end users. In normal declarations, authors take priority: they know
their design. But an accessibility user who has configured their browser to
display large text, high-contrast colours, or a specific font must be able to
override the author unconditionally. Marking their stylesheet rules !important
pushes them above the author, and the user-agent’s own !important rules (for
browser UI consistency) sit above even that.
Where cascade layers fit
@layer subdivides the author normal and author !important tiers only.
It does not interact with user or user-agent styles. Within author normal, the
declared layer order wins: rules in a later-declared layer beat those in an
earlier one, regardless of specificity. Unlayered author styles are treated as
belonging to an implicit top layer that beats all explicitly named layers.
Under !important, the layer order reverses — the same mirror that applies at
the origin level. A rule in the earliest-declared layer gets the highest
!important priority, which means framework resets marked !important can be
safely overridden by user code even in the important tier.
Debugging a rule that “won’t apply”
If a style is not applying despite an apparently winning selector, work through this checklist in order:
- Is a transition or animation currently running on the property? Transitions sit at tier 1 and will visually override everything during their duration.
- Is a browser user-stylesheet or accessibility extension adding a
!importantrule? Those sit at tiers 2 and 3. - Did you mark something
!importantin your own stylesheet that is now blocking the new rule? - Only after clearing these should you investigate specificity and source order.
Tips and notes
A transition always wins so animation never jams behind a static !important
rule. Within author styles, unlayered declarations beat layered ones for normal
rules — but that too reverses under !important. If a rule “won’t apply” despite
high specificity, check whether something higher in this origin table (often a
user-agent or user !important) is quietly outranking it. The comparison tool
below resolves any two declarations for you.