Skip to content
juniordev4life
Go back

The 2026 CSS You Can Finally Use

Be honest: when did you last check whether that CSS feature you dismissed two years ago is now safe to use?

Most of us carry a mental list of “nice, but not yet” - features we read about, filed under someday, and never revisited. Meanwhile the browsers quietly shipped them. In 2026 a whole batch crossed the line into Baseline, and several of them delete workarounds we have been maintaining for years.

This continues my CSS series here - cascade layers as a team contract, container queries for real responsive design. Same spirit: what actually changed, what it replaces, and how to decide when something is safe.

First: how to read “Baseline”

Before the features, the mental model - because this is the part that saves you from guessing forever.

Baseline describes interoperable support across the major browser engines:

That distinction is your adoption dial. Newly available features are ready for progressive enhancement today (add polish where supported, degrade gracefully elsewhere). Widely available features are ready for load-bearing use. Everything below is Newly available - which means: use it, but let it enhance rather than carry.

@scope — the missing piece next to cascade layers

If you have used cascade layers, @scope is the other half of the story. Layers decide which group of styles wins. Scope decides where a style applies - a real styling boundary without naming conventions or a CSS-in-JS runtime.

@scope (.card) to (.card-content) {
  /* Applies inside .card — but stops at .card-content */
  img {
    border-radius: 0.5rem;
  }
}

Look at what that kills: the BEM discipline you maintained by hand, the .card .card__media img selector chains, the fear that a bare img rule leaks somewhere unexpected. You get an explicit boundary - including a donut hole (to (...)), which nothing else in CSS could express. Firefox joined Chrome and Safari this year, and it is Baseline Newly available.

Container style queries — theming without class gymnastics

Container queries let you respond to a container’s size. Style queries let you respond to a container’s custom property values - which is a different and surprisingly powerful thing:

.panel {
  --theme: dark;
}

@container style(--theme: dark) {
  .card {
    background: #1a1a1a;
    color: #fff;
  }
}

A parent sets a semantic value; descendants adapt. No theme class threaded through every child, no JavaScript syncing state into class names. Firefox 151 completed engine support in May 2026, making this Baseline Newly available.

It pairs beautifully with design tokens: your semantic token sets the intent on a container, and the components downstream simply respond.

:open — stop tracking state you already have

Styling <dialog> and <details> used to mean checking attributes or - worse - toggling a class from JavaScript to mirror state the browser already knew. :open matches these elements exactly when they are open:

details:open summary {
  font-weight: 600;
}

dialog:open {
  animation: slide-in 200ms ease-out;
}

Small feature, disproportionate cleanup: every classList.toggle("is-open") you wrote to mirror native state can go. This is the same theme as my “delete a dependency” post - the platform absorbing the glue code we wrote around it.

contrast-color() — accessible text, computed

This one I am genuinely happy about. Given a background, contrast-color() picks a foreground that contrasts with it:

.badge {
  background: var(--badge-bg);
  color: contrast-color(var(--badge-bg));
}

Think about where that matters: user-chosen colours, tenant theming, data visualizations, tag colours from a CMS. Previously you either precomputed pairs, shipped a JS luminance calculation, or quietly hoped. Now the browser does it.

A caveat worth stating plainly: this handles the mechanical contrast decision, not your whole accessibility duty. It is a good default for dynamic colours - not a substitute for designing a palette that meets your contrast targets deliberately.

Custom highlights — styling ranges without wrecking the DOM

The last one is niche until you need it, and then it is the difference between clean and horrible. Custom Highlight API lets you define text ranges in JavaScript and style them via ::highlight() - without inserting <span>s into the DOM:

const highlight = new Highlight(range1, range2);
CSS.highlightRegistry.set("search-hit", highlight);
::highlight(search-hit) {
  background: yellow;
}

If you have ever implemented search-result highlighting by splitting text nodes and injecting wrappers - and then watched it fight your editor, your selection handling, and your screen reader - you know exactly why this matters.

What this means practically

Two takeaways I would hand a team this quarter:

  1. Revisit your “not yet” list. Most developers’ mental compatibility model is two years stale. The features above cost workarounds you are still maintaining today.
  2. Adopt as enhancement, not foundation. Newly available means interop is real but installed-base lag is not zero. Use these to make the good experience better - never to make the basic experience work. That is the same progressive-enhancement stance I took for view transitions, and it is what makes adopting new CSS a no-risk decision rather than a bet.

The tools that arrived while you were building

Every craftsperson knows the feeling: you develop a technique for a problem your tools could not solve - a jig, a workaround, a clever hack you are quietly proud of. It works. It becomes muscle memory. And you keep doing it for years after the workshop quietly stocked the proper tool for that exact job.

The hack is not wrong. It is just no longer necessary - and the cost of not noticing is not dramatic, which is precisely why it lasts so long: a little more effort, every single time, forever.

CSS is that workshop right now. @scope replaces your naming discipline. Style queries replace your theme-class plumbing. :open replaces your state mirroring. contrast-color() replaces your luminance math.

Walk the shelves once a year. The tool you have been improvising around may have been sitting there for months.


Share this post:

Previous Post
Your AI Feature Is a Gamble Until You Can Measure It
Next Post
Interviewing Developers When AI Writes the Code