Modern CSS Patterns That Reduce JavaScript
Container queries, native nesting, and resilient layout patterns for components that adapt without runtime measurement.
Design components around available space
Viewport breakpoints answer a page-level question. Reusable components often need a different answer: how much space does this component have here? Container queries let the component respond to its own layout context instead of reading dimensions in JavaScript.
.card-container {
container-type: inline-size;
}
@container (min-width: 32rem) {
.card {
grid-template-columns: 10rem 1fr;
}
}
This keeps layout rules close to the component and makes it safer to move between a sidebar, a grid, and a full-width section.
Use native nesting with restraint
Native nesting can make states easier to scan when it stays shallow:
.button {
background: var(--action-bg);
&:hover {
background: var(--action-bg-hover);
}
&:focus-visible {
outline: 3px solid var(--focus-ring);
outline-offset: 3px;
}
}
If selectors become difficult to read without reconstructing their full path, flatten them. Nesting should reduce context switching, not hide specificity.
Prefer resilient primitives
Grid, flexbox, minmax(), clamp(), and logical properties cover many layouts that once depended on resize listeners. They are easier to test, respond to writing modes, and avoid layout reads during rendering.
The practical rule is simple: use CSS for presentation and spatial adaptation; reserve JavaScript for behavior and state.
Further reading: MDN container queries and CSS nesting.