## CSS @layer: The Specificity Problem is Solved CSS specificity wars have plagued developers for decades. `!important` hacks, overly specific selectors, and CSS-in-JS escape hatches were common workarounds. In 2026, `@layer` is universally supported and fundamentally changes how we organize styles. ## Browser Support (2026) | Browser | Support | Notes | |---------|---------|-------| | Chrome 99+ | Full | Since March 2022 | | Edge 99+ | Full | Chromium-based | | Firefox 97+ | Full | Since Feb 2022 | | Safari 15.4+ | Full | Since March 2022 | **Global support: ~98%** You can use `@layer` everywhere without fallbacks. ## The Problem @layer Solves ### Before: Specificity Nightmares ```css /* Framework styles */ .btn { color: blue; } /* Your styles - same specificity, depends on order */ .btn { color: red; } /* Later addition - needs higher specificity */ button.btn { color: green; } /* Desperation */ .btn { color: purple !important; } ``` ### After: Explicit Layer Order ```css @layer framework, components, utilities; @layer framework { .btn { color: blue; } } @layer components { /* Always wins over framework, regardless of specificity */ .btn { color: red; } } @layer utilities { /* Always wins over components */ .btn { color: green; } } ``` ## How @layer Works ### Layer Order = Priority Later layers beat earlier layers, regardless of selector specificity: ```css /* Declare order upfront */ @layer reset, base, components, utilities; @layer reset { /* Lowest priority */ * { margin: 0; padding: 0; } } @layer utilities { /* Highest priority */ .hidden { display: none !important; } } ``` ### Anonymous Layers Styles outside any layer have highest priority: ```css @layer base { .card { background: white; } } /* Unlayered styles beat ALL layers */ .card { background: gray; } ``` ## Production Patterns ### Pattern 1: Framework Integration ```css /* Define layer order */ @layer reset, vendor, components, utilities, overrides; /* Import framework into vendor layer */ @import url('normalize.css') layer(vendor); @import url('tailwind-base.css') layer(vendor); @layer components { /* Your component styles always beat vendor */ .card { /* Don't need higher specificity */ } } @layer overrides { /* Quick fixes that beat everything layered */ .legacy-fix { margin-top: 10px; } } ``` ### Pattern 2: Component Library Architecture ```css @layer tokens, base, layout, components, variants, utilities; @layer tokens { :root { --color-primary: #3b82f6; --spacing-md: 1rem; } } @layer base { body { font-family: system-ui; } h1, h2, h3 { line-height: 1.2; } } @layer layout { .container { max-width: 1200px; margin: 0 auto; } .grid { display: grid; } } @layer components { .btn { padding: var(--spacing-md); } .card { border-radius: 8px; } } @layer variants { .btn--primary { background: var(--color-primary); } .btn--large { padding: calc(var(--spacing-md) * 1.5); } } @layer utilities { .mt-4 { margin-top: 1rem; } .hidden { display: none; } } ``` ### Pattern 3: Third-Party Style Isolation ```css @layer third-party, app; /* All third-party goes in one layer */ @layer third-party { @import url('some-widget.css'); @import url('date-picker.css'); } @layer app { /* Your styles always win */ .date-picker-override { /* Works without !important or specificity hacks */ } } ``` ### Pattern 4: Theme System ```css @layer theme-base, theme-dark, theme-overrides; @layer theme-base { :root { --bg: white; --text: #1a1a1a; } } @layer theme-dark { [data-theme="dark"] { --bg: #1a1a1a; --text: white; } } @layer theme-overrides { /* High-contrast mode, user preferences, etc. */ @media (prefers-contrast: high) { :root { --bg: white; --text: black; } } } ``` ## Nested Layers Layers can be nested for organization: ```css @layer components { @layer buttons { .btn { /* ... */ } } @layer cards { .card { /* ... */ } } } /* Reference nested layers with dot notation */ @layer components.buttons { .btn-new { /* ... */ } } ``` ## @layer with @import Import external stylesheets into specific layers: ```css /* Method 1: In @import statement */ @import url('bootstrap.css') layer(vendor); /* Method 2: Wrap imports */ @layer vendor { @import url('bootstrap.css'); } /* With media queries */ @import url('print.css') layer(print) print; ``` ## Combining with Other Modern CSS ### With CSS Nesting ```css @layer components { .card { padding: 1rem; .card-header { font-weight: bold; } &:hover { box-shadow: 0 4px 6px rgba(0,0,0,0.1); } } } ``` ### With Container Queries ```css @layer components { .card-container { container: card / inline-size; } @container card (width > 400px) { .card { flex-direction: row; } } } ``` ## Migration Strategy ### Step 1: Audit Current Styles Identify your current cascade issues: - Where do you use `!important`? - Where do you rely on selector specificity? - Which third-party styles conflict? ### Step 2: Define Layer Structure ```css /* Start simple */ @layer reset, vendor, base, components, utilities, overrides; ``` ### Step 3: Gradually Migrate ```css /* Move existing styles into layers */ @layer base { /* Existing base styles */ } @layer components { /* Existing component styles */ } /* Keep unlayered styles for debugging */ .temporary-fix { /* Still works, highest priority */ } ``` ### Step 4: Remove Specificity Hacks ```css /* Before */ .sidebar .nav .nav-item.active a { color: blue; } /* After */ @layer components { .nav-link.active { color: blue; } } ``` ## Common Mistakes ### Mistake 1: Order Declaration Without Styles ```css /* ❌ This only declares order */ @layer a, b, c; /* Styles still need to be added */ @layer a { /* ... */ } ``` ### Mistake 2: Forgetting Unlayered Priority ```css @layer components { .btn { background: blue; } } /* ❌ This ALWAYS wins - might be unintentional */ .btn { background: red; } ``` ### Mistake 3: Over-Nesting Layers ```css /* ❌ Too complex */ @layer components.forms.inputs.text.validation { } /* ✅ Keep it flat when possible */ @layer components { .input-validation { } } ``` ## Key Takeaways 1. **Universal support** - 98% browser coverage, use it now 2. **Order beats specificity** - Later layers always win 3. **Unlayered wins all** - Styles outside layers have highest priority 4. **Framework isolation** - Import third-party CSS into dedicated layers 5. **Gradual migration** - Add layers incrementally to existing projects `@layer` is the CSS feature that finally solves the cascade management problem. In 2026, there's no excuse for specificity wars or `!important` hacks. Layer your styles and reclaim control of your cascade.