"Why does my style not apply" is the cascade; "how do I lay this out" is grid and flexbox; "what is new" is the list below. A senior answers all three in terms of the mechanism, and knows which features are safe to ship without fallbacks in 2026.
@layer reset, base, components, utilities declares order once; a later layer wins regardless of specificity, and unlayered styles beat all layers. Layers replace the specificity wars that BEM and !important fought. :where() has zero specificity (resets), :is() takes the highest of its arguments.!important; !important inverts layer order. Nesting (&) is native; @scope (.card) to (.content) limits selectors to a subtree and stops "donut" leakage, with proximity resolving ties.@property registers a type so they animate and have a default; var(--x, fallback).margin-inline-start, inset-block, padding-block) follow writing direction; use them by default so RTL and vertical scripts work without duplicated rules.grid-template-areas, minmax(), auto-fit/auto-fill, repeat()); subgrid lets nested items align to the parent's tracks (cards with aligned titles and prices). gap works in both; aspect-ratio reserves space.container-type: inline-size on the parent, @container (min-width: 32rem) in the child, cqi/cqw units; components respond to their container, which is what media queries never did. :has() is the parent selector (.field:has(:invalid), li:has(> img)), also usable for state without JavaScript.oklch()/oklab() for perceptually uniform palettes, color-mix() for tints, light-dark() with color-scheme for theme values, relative colour syntax; text-wrap: balance/pretty, font-display, variable fonts, clamp() for fluid type.@starting-style plus transition-behavior: allow-discrete to animate display: none and popovers; scroll-driven animations (animation-timeline: scroll()/view()); view transitions same-document (document.startViewTransition, Nuxt's experimental.viewTransition) and cross-document (@view-transition { navigation: auto }); prefers-reduced-motion respected always.popover, popovertarget, top layer, light dismiss) and <dialog showModal()> (top layer, focus trapping, ::backdrop); anchor positioning (anchor-name, position-anchor, position-area, anchor(), position-try-fallbacks) is Baseline Newly available since January 2026 and replaces Popper/Floating UI for tooltips and menus where the browser matrix allows.contain, content-visibility: auto for long pages, will-change sparingly, animate transform/opacity, avoid layout-triggering properties in animations, field-sizing: content for auto-growing inputs.@supports for progressive enhancement; the if() function and a few others are shipping but not Baseline yet.@layer reset, tokens, base, components, utilities;
@layer tokens {
:root {
color-scheme: light dark;
--space-3: 0.75rem;
--radius: 0.5rem;
--brand: oklch(62% 0.19 260);
--bg: light-dark(oklch(99% 0 0), oklch(18% 0.02 260));
--text: light-dark(oklch(20% 0.02 260), oklch(95% 0.01 260));
}
@property --progress { syntax: '<percentage>'; inherits: false; initial-value: 0%; }
}
@layer components {
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
gap: var(--space-3);
}
.product {
container-type: inline-size;
display: grid;
grid-template-rows: subgrid; /* align title/price rows across cards */
grid-row: span 3;
border-radius: var(--radius);
background: color-mix(in oklch, var(--bg) 96%, var(--brand));
padding-inline: var(--space-3); /* logical: flips for RTL */
&:has(.badge--sale) { outline: 2px solid var(--brand); }
.title { text-wrap: balance; font-size: clamp(1rem, 0.9rem + 1cqi, 1.25rem); }
@container (min-width: 24rem) { grid-template-columns: 1fr auto; }
}
}
@scope (.product) to (.reviews) {
a { color: var(--brand); } /* styles product links but not links inside nested .reviews */
}
@layer utilities {
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
A tooltip with anchor positioning and popover, no JavaScript positioning library:
<script setup lang="ts">
const id = useId()
</script>
<template>
<button type="button" :popovertarget="id" :style="{ anchorName: `--tip-${id}` }"><slot name="trigger" /></button>
<div :id="id" popover role="tooltip" class="tip" :style="{ positionAnchor: `--tip-${id}` }"><slot /></div>
</template>
<style scoped>
.tip {
position-area: top center;
position-try-fallbacks: flip-block; /* flip below when there is no room above */
margin: 0; inset: auto;
@starting-style { opacity: 0; }
transition: opacity 0.12s, display 0.12s allow-discrete;
}
@supports not (position-area: top) {
.tip { position: fixed; inset: auto 1rem 1rem auto; } /* graceful fallback */
}
</style>
!important declarations flip the layer order: an important declaration in an earlier layer beats an important one in a later layer. If you adopt layers, ban !important except in a documented utilities layer, or the mental model breaks.
@container rules silently do nothing when no ancestor has container-type. Set container-type: inline-size on the component root (not on the element being sized), and remember that a container's size cannot depend on its contents on the queried axis.
Current Baseline status for anchor positioning (Newly available since January 2026), the CSS if() function, cross-document view transitions and field-sizing; check the interview week.
@layer and remove every !important; verify the order with the DevTools Styles panel.@supports fallback and test in a browser without support."The cascade, in order: origin and importance first, then cascade layers, then specificity, then source order. Layers are the modern control: I declare @layer reset, base, components, utilities once, and a rule in a later layer wins over any specificity in an earlier one, while unlayered styles beat all layers. Within a layer specificity is ids, then classes, attributes and pseudo-classes, then elements, with :where() contributing zero and :is() the maximum of its arguments. Inline styles beat everything except !important, which inverts the layer order, which is why I ban it outside a utilities layer. And @scope adds proximity as a tie-breaker inside a subtree."
"Container queries so components respond to their own width, :has() for parent and state selectors, cascade layers for order, native nesting and @scope for structure, logical properties for RTL, oklch and color-mix for palettes with light-dark() for themes, clamp() and text-wrap: balance for typography, @starting-style with discrete transitions for popovers, and view transitions for navigation where motion is welcome. Anchor positioning became Baseline in January 2026, so I use it for tooltips and menus with an @supports fallback, and I check Baseline before adopting anything newer such as if()."
Nothing yet. Notes filed here show up on this page and the section overview.
CSS, layout & accessibility
Why senior frontend interviews still test CSS and accessibility, the 2026 platform baseline, and how the pages on the cascade and modern layout, CSS architecture with Tailwind v4, responsive design, WCAG 2.2 and accessible components in Vue fit together.
CSS architecture and Tailwind v4
Ownership models for styles — scoped SFC styles, CSS Modules, utility-first with Tailwind v4's CSS-first configuration, design tokens as custom properties, theming and dark mode, how Nuxt UI composes Tailwind variants with app.config tokens, and what happened to BEM and CSS-in-JS.