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).
Jump to the interview angleAdvanced 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.
/* 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.
/* 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.
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.
Interview angle
Interviewers test whether you reach for a methodology (BEM, ITCSS) or a JS workaround before checking whether CSS can do it natively. Knowing when @layer beats specificity hacks and when :has() replaces a state toggle is the differentiator.
Soundbite: "@layer makes specificity a deliberate decision, not an accidental arms race."
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.