# Advanced CSS Architecture > Native CSS features that replace methodology and JS for cascade control. Frontend architecture guidance from fearchitect, written by Abas Turabli and last reviewed 2026-06-21. Source: https://fearchitect.com/topics/advanced-css-architecture Use it as reference for the task at hand. Before changing code, check this guidance against the codebase: where the code already makes a different, deliberate choice, flag the conflict instead of rewriting it. Library APIs move faster than this guide, so confirm exact signatures in the official docs linked at the end. ## Summary Modern CSS — `@layer`, container queries, `:has()`, `:is()`/`:where()`, and subgrid — gives you explicit cascade management, component-scoped layout, and relational selection without BEM discipline or JavaScript. All five are widely supported across current browsers; check Baseline before dropping fallbacks for the newest of them (`:has()`, subgrid). ## Advanced CSS architecture A set of native CSS features — `@layer`, `@container`, `:has()`, `:is()`/`:where()`, and subgrid — that handle cascade management, component-scoped layout, and relational selection without naming methodologies or JavaScript state toggles. All five are widely supported in current browsers; check Baseline for the newest before dropping fallbacks. ## What each feature replaces - `@layer` replaces specificity arms races and ITCSS import order discipline. - `@container` replaces JS resize observers for component-scoped breakpoints. - `:has()` replaces JS event listeners that add classes to parent elements. - `:is()` / `:where()` replace long comma selector lists with cleaner, specificity-controlled groupings. - Subgrid replaces duplicate grid definitions in nested components to stay aligned. ## `@layer` + `@container` in a design-system component Declare layers once at the top of your entry stylesheet. Lower layers always lose to higher ones, so a reset rule in `base` can never override a component rule in `components`, even with a higher-specificity selector. **Card component using @layer and @container** ```css /* entry.css — layer order declaration (lowest → highest) */ @layer base, tokens, components, utilities; /* base reset: high-specificity selectors still lose to 'components' */ @layer base { *, *::before, *::after { box-sizing: border-box; } img { max-width: 100%; display: block; } } /* component: container query scope + subgrid */ @layer components { .card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.5rem; } .card { container-type: inline-size; container-name: card; display: grid; /* subgrid: participate in .card-grid's column tracks */ grid-column: span 1; } /* layout switches at the card's own width, not the viewport */ @container card (min-width: 420px) { .card__inner { display: grid; grid-template-columns: 160px 1fr; gap: 1rem; } } } /* utilities always win — declared last in layer order */ @layer utilities { .sr-only { position: absolute; width: 1px; height: 1px; clip: rect(0, 0, 0, 0); overflow: hidden; } } ``` The layer order declaration on line 2 is the only place you manage cascade priority. Adding a new layer later just slots into that order — no specificity debugging needed. ## `:has()` for relational selection without JS `:has()` matches a subject element based on what it contains. Supported across all major browsers — check Baseline/caniuse if you must support older versions. **Form validation state and nav badge via :has()** ```css /* Style the form itself when it contains an invalid input */ form:has(input:invalid) { border: 2px solid hsl(0 80% 55%); } /* Parent li gets active styling when its link is current-page */ nav li:has(> a[aria-current="page"]) { background: hsl(220 90% 95%); font-weight: 600; } /* Figure gets extra padding when it contains a caption */ figure:has(figcaption) { padding-block-end: 0.5rem; } /* :where() for zero-specificity base: easy to override */ :where(h1, h2, h3, h4) { line-height: 1.2; text-wrap: balance; } /* :is() for grouped rules — specificity = :is()'s highest arg (0,1,0) */ :is(article, section, aside) > p { max-width: 68ch; } ``` `:where()` at zero specificity is ideal for resets; `:is()` is ideal for grouping rules where you want normal specificity to apply. ## Note: Browser support `@layer`, `@container`, `:is()`/`:where()`, and subgrid are all interoperable across current Chrome, Firefox, and Safari; `:has()` is the newest of the group but is also widely supported now. Check Baseline or caniuse before dropping fallbacks if you still support older browser versions. ## Key terms - **@layer**: CSS at-rule that groups rules into named cascade layers, lower layers losing to higher ones regardless of specificity. - **container query**: Rule that applies styles based on a parent container's size, not the viewport. - **:has()**: Relational pseudo-class that matches an element if it contains a specific descendant or sibling. - **:is() / :where()**: Forgiving selector lists; `:is()` takes the highest specificity of its args, `:where()` contributes zero specificity. - **subgrid**: CSS Grid value (`grid-template-columns: subgrid`) that lets a child participate in its ancestor's grid tracks. ## Related topics - [Design Tokens & Theming](https://fearchitect.com/topics/design-tokens-theming.md): Named design decisions that flow from source to every platform. - [Atomic / Utility-First CSS](https://fearchitect.com/topics/atomic-utility-first-css.md): Single-purpose classes that compose styles without growing a stylesheet. - [CSS Modules vs CSS-in-JS vs Tailwind](https://fearchitect.com/topics/css-modules-vs-css-in-js-vs-tailwind.md): CSS Modules, CSS-in-JS, and utility-first — by runtime cost and RSC fit. - [Design Systems](https://fearchitect.com/topics/design-system.md): A shared product — tokens, components, docs, and governance — at scale. - [Component Architecture & Project Structure](https://fearchitect.com/topics/component-architecture.md): Structuring components so composition beats configuration. - [View Transitions & Scroll Animations](https://fearchitect.com/topics/view-transitions-scroll-animations.md): CSS-native page transitions and scroll-driven animations without JavaScript. ## Further reading - [MDN — @layer](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer) - [MDN — CSS container queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries) - [MDN — :has()](https://developer.mozilla.org/en-US/docs/Web/CSS/:has) - [MDN — subgrid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid) - [MDN — Cascade layers (learn)](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Cascade_layers)