·7 min read

CSS in 2026: container queries, view transitions, OKLCH

The CSS features that finally make 2026 different: container queries for components, OKLCH for palettes, view transitions for routes, and :has() for sanity.

CSSDesign SystemsFrontend

I’ve been writing CSS for a decade and the last two years feel like more change than the previous eight combined. Container queries, the View Transition API, native CSS nesting, OKLCH colours, scope, has(), anchor positioning, scroll-driven animations. Most of these are already in every shipping browser. If you’re still writing CSS the way you did in 2022, you’re leaving a lot on the table.

Container queries change layout

Media queries asked: how big is the viewport? Container queries ask the question that actually matters: how big is the space this component lives in? A card that sits in a sidebar should render differently from the same card stretched across a hero, and you should not need a prop, a class, or a JavaScript measurement to do it.

.card-host { container-type: inline-size; }

.card { display: grid; gap: 0.5rem; }

@container (min-width: 32rem) {
  .card { grid-template-columns: 12rem 1fr; }
}

The card becomes a self-contained piece of layout logic. Drop it into a 12-column grid, a 4-column grid, a sidebar, a modal: it adapts. You stop reaching for JavaScript measurement libraries.

OKLCH is the colour space worth learning

OKLCH gives you lightness, chroma, and hue, and unlike HSL the values actually correspond to how humans perceive colour. Two OKLCH colours with the same lightness look like the same lightness. Generate a palette by varying the lightness while holding chroma and hue, and the result is a real ramp instead of an uneven smear.

For this site I’m using a single accent at oklch(0.72 0.18 35)and pulling the surface and ink ramps out of a near-neutral base. The palette stays coherent under dark mode and light mode because the lightness axis behaves predictably.

View Transitions for routes and lists

The View Transition API is the closest thing the web has had to native FLIP animations. You wrap a state change indocument.startViewTransition and the browser captures the before-and-after of the document, then cross-fades between them. Frameworks are wiring this in for route transitions; Next.js, Astro, Remix have all landed first-class support.

The trick is to use it sparingly. Apply it to one or two clearly motivated movements per page (a card expanding into a detail view, a list re-sorting) and respect prefers-reduced-motion. Animate everything and you end up with the JavaScript-driven SPA feel that the web spent five years trying to escape.

has(), nesting, and scope

:has() is the parent selector we waited ten years for. A form that knows whether it contains an invalid field, a card that knows whether it’s been hovered, a layout that knows whether a child has expanded: all of it possible without JavaScript or class toggling.

Native nesting reduces preprocessor lock-in. Scope lets you write styles that apply only inside a tree, without the global-namespace anxiety that fuelled the CSS-in-JS era. The combined effect: plain CSS files have become a serious choice again, even for large apps. A lot of teams I talk to are quietly migrating off CSS-in-JS in 2026.

What I’d ignore

Anchor positioning and scroll-driven animations are exciting but still moving. I keep an eye on them and I’ll reach for them when a real need appears, but I wouldn’t build a design system around them yet. The 2026 bet is container queries plus OKLCH plus view transitions plus:has(). Master those and the rest follows.

The web platform has caught up. Most of what we used to write JavaScript for is now a few lines of CSS. Lean in.