Organize Rules by Priority — Without `!important`
Cascade Layers
`@layer` groups rules into named priority bands. A rule in a later layer beats a rule in an earlier layer — regardless of specificity.
What you'll learn
- Declare and order layers
- Move third-party CSS into a low-priority layer
- Stop fighting specificity
@layer groups rules into named priority bands. Rules in a
later layer always beat rules in an earlier layer, regardless
of specificity. Inside a layer, specificity rules normally.
Declare Layers In Order
@layer reset, base, components, utilities; Order matters. Later in the list = higher priority.
Put Rules In Layers
@layer reset {
*, *::before, *::after { box-sizing: border-box; }
}
@layer base {
body { font-family: system-ui; line-height: 1.5; }
a { color: var(--brand); }
}
@layer components {
.btn { padding: 0.5rem 1rem; border-radius: 6px; }
}
@layer utilities {
.text-center { text-align: center; }
.hidden { display: none; }
} A utility like .text-center beats a .heading rule in
components, even though both are single-class selectors. Layers
trump specificity.
Third-Party CSS Into a Low Layer
@import url("third-party.css") layer(vendor);
@layer vendor, base, components, utilities; Vendor styles are now the LOWEST priority, even if they use high-specificity selectors. Your normal CSS beats them effortlessly.
Unlayered Styles
Styles NOT in any layer have priority OVER all layers. Useful for emergency overrides — but if you find yourself relying on this, your layer order is probably wrong.
When To Reach For Layers
- Big projects with mixed sources (vendor, base, components, utilities)
- Stop using
!importantto win specificity fights - Tailwind-style utility-first setups, where utilities should always win
For a small project with just your own CSS, layers can be overkill. Use them when complexity warrants.
Up Next
:has() — the parent selector everyone wanted for a decade.