App Commandos
CSS

Modern CSS in 2026: Container Queries, Cascade Layers, and the Features That Finally Shipped

Published March 10, 2026 • 6 min read • 1,177 words

CSS has changed more in the past three years than in the previous decade. Container queries, cascade layers, the :has() selector, and native nesting are all baseline-supported. Here is how to actually use them in production today.

The modern CSS toolset has expanded dramatically — most features that required JavaScript or preprocessors in 2020 are now native in 2026
The modern CSS toolset has expanded dramatically — most features that required JavaScript or preprocessors in 2020 are now native in 2026

CSS has undergone a transformation in the past three years that is genuinely difficult to overstate. Features that frontend developers had been requesting for a decade — container queries, cascade layers, native nesting, the :has() selector — are now baseline-supported across Chrome, Firefox, Safari, and Edge. The preprocessor hacks and JavaScript workarounds that held entire codebases together are, in many cases, no longer necessary.

This post covers the CSS features that have crossed the baseline threshold and are safe to use in production today, with practical examples and guidance on when to reach for each one.

Container Queries: The Layout Revolution

For years, responsive design meant responding to the viewport — media queries that fired at specific screen widths. The fundamental problem: a component does not know how much space its container has given it. A card component inside a narrow sidebar needs different layout than the same card inside a full-width grid, but @media queries could not express that.

Container queries solve this at the CSS level:

.card-wrapper {
    container-type: inline-size;
    container-name: card;
}

@container card (min-width: 400px) {
    .card {
        display: grid;
        grid-template-columns: 120px 1fr;
        gap: 1rem;
    }
}

The .card component now responds to its container's width, not the viewport. This makes components genuinely reusable — the same markup and CSS produces the correct layout whether placed in a sidebar, a full-width hero, or a nested grid.

Container queries shipped in all major browsers in 2022 and 2023. Browser support is excellent and has been stable for three years. If you are not using them in 2026, you are writing more layout CSS than you need to.

Container Query Units

Alongside @container, CSS introduced container-relative units:

  • cqi — 1% of the container's inline size
  • cqb — 1% of the container's block size
  • cqw, cqh, cqmin, cqmax — similar viewport-relative analogs but container-scoped

These are useful for typography that should scale with the component rather than the viewport.

Cascade Layers: Taming Specificity

The cascade is CSS's most misunderstood feature and the source of most !important abuse. Cascade layers give you explicit control over the order in which style groups are resolved, regardless of specificity:

@layer reset, base, components, utilities;

@layer reset {
    *, *::before, *::after { box-sizing: border-box; }
    margin: 0; padding: 0;
}

@layer components {
    .btn {
        display: inline-flex;
        padding: 0.5rem 1.25rem;
        border-radius: 6px;
    }
}

@layer utilities {
    .mt-4 { margin-top: 1rem; }
}

Styles in later layers win over earlier layers regardless of specificity. A class selector in utilities overrides an ID selector in components because utilities is declared last in the layer order.

This changes how you structure CSS at scale. Instead of fighting specificity battles with increasingly specific selectors, you define the layer order once and trust it. Third-party CSS can be wrapped in a layer so it never interferes with your component styles:

@import url('vendor-library.css') layer(vendor);
@layer vendor, base, components, utilities;
Container queries let components respond to their own available space, not the viewport width
Container queries let components respond to their own available space, not the viewport width

CSS Nesting: Native and Stable

CSS nesting has been supported natively since Chrome 112, Firefox 117, and Safari 17.2 — all released in 2023. It works the same way preprocessors like Sass taught developers to write it:

.nav {
    display: flex;
    gap: 1rem;

    & a {
        color: inherit;
        text-decoration: none;

        &:hover {
            text-decoration: underline;
        }
    }

    @media (max-width: 768px) {
        flex-direction: column;
    }
}

The & refers to the parent selector. Media queries inside a rule apply only to that element. This is native CSS — no build step required, though build tools like PostCSS and Lightning CSS will still transpile it for older targets if needed.

Sass and PostCSS are no longer required for nesting alone. If nesting was your primary reason for using a preprocessor, you may not need one.

The :has() Selector

:has() is a relational pseudo-class that selects an element based on its descendants. It effectively inverts the CSS selector model — instead of only styling children based on parents, you can now style parents based on children:

/* Card with an image gets a different layout */
.card:has(img) {
    display: grid;
    grid-template-columns: 200px 1fr;
}

/* Form field with an error message gets red border */
.field:has(.error-message) {
    border-color: red;
}

/* Nav item that is currently active */
li:has(a[aria-current="page"]) {
    background: #f0f5ff;
}

This replaces patterns that previously required JavaScript class toggling. :has() has been baseline-supported across all major browsers since December 2023.

color-mix() and oklch()

CSS color tools have matured significantly. Two additions are particularly useful in production:

color-mix()

.surface {
    background: color-mix(in srgb, var(--brand-color) 20%, white);
}

color-mix() blends two colors in a specified color space. This replaces Sass's lighten() and darken() functions with a native equivalent that works inside custom properties.

oklch()

oklch() is a perceptually uniform color space that makes color manipulation predictable:

:root {
    --brand: oklch(55% 0.2 250);
    --brand-light: oklch(75% 0.15 250);
    --brand-dark: oklch(35% 0.22 250);
}

When you adjust lightness in oklch, the perceived brightness changes uniformly — something hsl() fails at for saturated colors. Design systems built on oklch produce more consistent results when generating tints and shades programmatically.

Cascade layers replace specificity wars with an explicit, predictable style resolution order
Cascade layers replace specificity wars with an explicit, predictable style resolution order

CSS @scope

@scope allows you to limit where a set of styles apply, scoping them to a subtree of the DOM:

@scope (.article-body) to (aside) {
    h2 { font-size: 1.5rem; color: #1a2c1e; }
    p { line-height: 1.75; }
}

The optional to (aside) clause creates a "scope boundary" — the styles stop applying when an aside element is encountered inside .article-body. This is valuable for content areas where you want to style arbitrary HTML without leaking styles into widgets or sidebars embedded within.

CSS Anchor Positioning

Anchor positioning is one of the most anticipated additions to CSS in recent years and reached baseline in late 2025. It allows you to position an element relative to another element anywhere in the DOM — not just its parent:

.tooltip {
    position-anchor: --button;
    top: anchor(bottom);
    left: anchor(center);
    translate: -50% 0;
}

This eliminates the need for JavaScript-based popover positioning libraries for tooltips, dropdowns, and floating panels. Combined with the Popover API, it provides a fully native solution for a UI pattern that previously required dependencies like Floating UI or Popper.js.

Native CSS nesting, :has(), and anchor positioning reduce dependency on JavaScript for layout
Native CSS nesting, :has(), and anchor positioning reduce dependency on JavaScript for layout

What You Can Stop Using

Given all of the above, several tools that were essential in 2020 can be retired or significantly reduced:

Old Approach Native Replacement
JS for parent-based styles :has() selector
Sass for nesting Native CSS nesting
Sass lighten() / darken() color-mix(), oklch()
JS layout toggling by container Container queries
!important specificity battles Cascade layers
Popper.js / Floating UI Anchor positioning

You do not need to rewrite existing code overnight. But for new components and projects, reaching for these native features first reduces build complexity and eliminates runtime JavaScript for styling concerns.

Conclusion

CSS in 2026 is a genuinely powerful layout and styling language without requiring a build pipeline, a runtime library, or a preprocessor for most use cases. Container queries, cascade layers, native nesting, :has(), oklch(), and anchor positioning are not experimental features — they are stable, baseline-supported, and ready for production.

The best approach to modern CSS is incremental adoption: add container queries to your next new component, move your layer order declaration to the top of your stylesheet, start using oklch() in your next design token update. Each of these improvements can be adopted independently without a full rewrite.