Modern CSS in 2026: What Actually Shipped
Quick answer: :has(), container queries and CSS nesting are safe everywhere. Anchor positioning and @starting-style work in all three engines but are recent enough to need a fallback. @function is Chromium-only. And native CSS mixins have not shipped in any browser — despite a run of 2026 articles saying otherwise.
Every January a wave of “CSS features coming this year” posts arrives, and most of them are a list of specification drafts with no support column. That is how @mixin ended up in a dozen “what shipped in 2026” listicles while remaining unimplemented in every browser on earth.
This is the version with the support column. Four tiers: what is genuinely safe, what is new enough to guard, what only Chromium has, and what has not shipped at all. Plus a probe that tests your own browser, live, as you read.
Let’s start with the correction
MDN’s page for CSS custom functions and mixins states it plainly: “CSS mixins are not currently supported in any browser.” The same note covers @apply, @contents and @env — none of them are implemented anywhere.
What did ship is the neighbouring feature, and the confusion is understandable because they live in the same specification. @function shipped in Chrome and Edge 139. It lets you define a named function that takes arguments and returns a value:
@function --negate(--value) {
result: calc(var(--value) * -1);
}
.card {
margin-top: --negate(var(--gap));
}
That is real, and it works today in Chromium. Firefox and Safari have not shipped it. So @function is a progressive enhancement, not a Sass replacement — and @mixin, the part that would actually replace Sass mixins, is still a draft. Chrome originally targeted version 136 for @function and delayed it to 139, which is a fair signal of how much of this area is still moving.
What does your browser support right now?
This runs CSS.supports() and a stylesheet parse test against your current browser. Nothing is sent anywhere — the answer comes from the engine rendering this page.
Live support check
Your browser, this second.
Running…
How Baseline actually works
Baseline is a status label for web features, maintained by the W3C WebDX Community Group, describing how broadly a feature is supported across Chrome, Edge, Firefox and Safari. It has two levels, and the difference is the whole point:
- Baseline Newly available — the feature works in all three engines as of some date. Usable, but anyone who has not updated their browser will miss it.
- Baseline Widely available — 30 months have passed since that date. At that point the long tail of un-updated browsers has largely aged out, and you can generally use the feature without a fallback.
Thirty months is a long time, and it is the number that turns “supported in all browsers” into “safe to ship without thinking about it.” Container queries became newly available in February 2023 and widely available in August 2025. :has() became newly available in December 2023 and crossed into widely available in June 2026 — this year.
Tier 1: Safe to use with no fallback
All Baseline Widely available. Use them the way you use flexbox.
| Feature | What it replaces | Status |
|---|---|---|
:has() | A JavaScript listener that adds a class to a parent | Widely available, June 2026 |
| Container queries | Media queries for components that move between layouts | Widely available, August 2025 |
| CSS Nesting | Sass, for the nesting half of what Sass does | Widely available |
aspect-ratio | The padding-top percentage hack | Widely available |
| Subgrid | Manual width matching between grid children | Widely available |
clamp() | Breakpoint-by-breakpoint font sizing | Widely available |
:is(), :where() | Long selector lists, and specificity workarounds | Widely available |
@layer | Specificity wars and !important | Widely available |
| OKLCH color | Hex ramps that go muddy in the middle | Widely available |
:where() deserves a specific mention because it is the cheapest fix in modern CSS: it contributes zero specificity. Wrapping a reset or a library override in :where() means anything you write later can beat it with a single class. That is the direct antidote to the jagged specificity graph that most stylesheets develop.
Tier 2: Shipped everywhere, but recently — guard it
These work in all three engines and are Baseline Newly available. The feature is real; the risk is the user on a browser from last year.
| Feature | Chrome / Edge | Firefox | Safari |
|---|---|---|---|
| Anchor positioning | 125 | 147 | 26 |
@starting-style | 117 | 129 | 17.5 |
| Style queries (custom properties) | 111 | 151 | 18 |
Anchor positioning is the headline of 2026 — it had the largest year-over-year usage increase of any feature in the State of CSS 2026 survey, up 15%. It tethers one element’s position to another’s without JavaScript, which retires the reason most sites load a positioning library for tooltips, dropdowns and popovers. Firefox enabled it by default in version 147; Safari shipped it in 26. Can I Use puts global coverage around 84%.
That 84% is exactly why you guard it:
.tooltip {
/* fallback: fine everywhere */
position: absolute;
inset-block-start: 100%;
}
@supports (anchor-name: --x) {
.trigger { anchor-name: --trigger; }
.tooltip {
position-anchor: --trigger;
position-area: block-end center;
position-try-fallbacks: flip-block;
}
}
@starting-style is the other one worth adopting now. It defines the styles an element has before its first render, which finally makes it possible to animate something in from display: none without a JavaScript timing hack:
dialog[open] {
opacity: 1;
transition: opacity .25s, display .25s allow-discrete;
}
@starting-style {
dialog[open] { opacity: 0; }
}
It reached all three engines in August 2024 with Firefox 129, so it is close to the widely-available line but not across it yet.
Tier 3: Chromium only — enhancement, not architecture
Real, shipping, and available to roughly two thirds of users. Use them where absence degrades gracefully; never build a layout that requires them.
@function— Chrome and Edge 139. Custom functions with arguments and aresult.- Scroll-driven animations —
animation-timeline: scroll()andview(). A scroll progress bar in three lines of CSS, with no scroll listener and no layout thrash. field-sizing: content— textareas that grow with their content, replacing a well-worn JavaScript snippet.- Cross-document view transitions — animate between two full page loads on a multi-page site.
Scroll-driven animations are the standout here, because the fallback is simply “nothing moves” — which is an acceptable outcome, and is what a user with prefers-reduced-motion should get anyway.
Tier 4: Not shipped, whatever you read
| Feature | Reality |
|---|---|
@mixin / @apply | No browser support anywhere. Draft specification. |
@contents, @env | No browser support anywhere. |
if() | Among the least-used features in State of CSS 2026, on limited support. |
| Gap decorations | Also among the least-used, for the same reason. |
sibling-count() | Awareness rose 22% year over year — awareness, not support. |
The sibling-count() line is worth pausing on, because it captures the whole problem. A feature can be the most-discussed thing in CSS and still be unusable. Discussion volume and support are independent variables, and only one of them decides whether your layout works.
What developers are really using
From the State of CSS 2026 survey, the most-used features by share of respondents:
| Feature | Have used it |
|---|---|
:has() | 83.7% |
aspect-ratio | 81.3% |
| CSS Nesting | 70.6% |
scroll-behavior | 68.2% |
| Viewport-relative units | 59.8% |
Note what is absent. Nothing exotic. The features that won are the ones that removed a specific, daily annoyance — a parent selector, an aspect-ratio hack, a build step for nesting. :has() is both the most used and the most loved, which is unusual; normally the most-loved feature is one people have barely tried.
How to see what a site actually ships
Reading about features is one thing. The more useful exercise is opening a site you admire and finding out which of these it really uses — because production CSS is a much better guide to what is safe than any survey.
This counts modern features in the page’s own stylesheets:
const CSS_TEXT = [...document.styleSheets]
.flatMap(s => { try { return [...s.cssRules] } catch { return [] } })
.map(r => r.cssText).join('\n');
const CHECKS = {
':has()': /:has\(/,
'container queries': /@container|container-type/,
'nesting': /&\s*[.:#\[]/,
'anchor positioning': /anchor-name|position-anchor|position-area/,
'@starting-style': /@starting-style/,
'cascade layers': /@layer/,
'OKLCH color': /oklch\(/,
'scroll-driven anim.': /animation-timeline/,
'subgrid': /subgrid/,
'clamp()': /clamp\(/,
'!important': /!important/
};
console.table(Object.entries(CHECKS).map(([feature, re]) => ({
feature,
found: re.test(CSS_TEXT) ? 'yes' : 'no'
})));
The try / catch matters: reading cssRules from a cross-origin stylesheet throws a SecurityError, and one uncaught throw kills the loop. Catching per sheet means a site serving CSS from a CDN still reports on everything same-origin.
Want this without the console? CSS DNA reads any page’s live styles and reports the palette, type scale, spacing, breakpoints, motion and custom properties in one click — then exports them as Tailwind, CSS variables, SCSS or design tokens. Add it free, and every site you open becomes a reference.
The honest summary
CSS in 2026 did absorb a genuine amount of what used to be JavaScript: parent selection, component-level responsiveness, entry animations, tethered positioning, scroll-linked motion. That part of the excitement is earned.
What has not happened is the wholesale replacement of the preprocessor. Nesting is native and colour functions are native, but mixins are not, and the practical shape of a 2026 stylesheet is still mostly Tier 1 features with a handful of guarded enhancements. Build with that and the site works for everyone — which was always the actual goal.
Frequently asked questions
Are native CSS mixins supported in browsers?
No. MDN states that CSS mixins are not currently supported in any browser, along with the related @apply, @contents and @env at-rules. The related @function rule did ship, in Chrome and Edge 139, but it returns a value rather than applying a block of declarations.
What does Baseline “widely available” mean?
Baseline Widely available means 30 months have passed since a feature became supported in Chrome, Edge, Firefox and Safari. That interval allows un-updated browsers to age out, so a widely available feature can generally be used without a fallback. Baseline Newly available means all three engines support it, but only recently.
Is the :has() selector safe to use in 2026?
Yes. :has() became Baseline Newly available in December 2023 and reached Baseline Widely available in June 2026. It is also the most-used feature in the State of CSS 2026 survey at 83.7%.
Which browsers support CSS anchor positioning?
Chrome and Edge from version 125, Firefox from 147, and Safari from 26. Can I Use puts global coverage at roughly 84%, so wrap it in @supports (anchor-name: --x) and provide a static fallback position.
What is @starting-style used for?
@starting-style defines the styles an element has before its first render, which lets you transition an element in from display: none without a JavaScript timing hack. It reached all three engines in August 2024 — Chrome 117, Safari 17.5, Firefox 129.
Does modern CSS replace Sass?
Partly. Nesting, custom properties, colour manipulation and cascade layers are all native now. Mixins are not supported in any browser, and @function is Chromium-only, so projects relying on those still need a preprocessor.
How do I check which CSS features a website uses?
Walk document.styleSheets, join every rule’s cssText, and test it against patterns such as /:has\(/ or /@container/. Wrap each sheet in try / catch, because reading rules from a cross-origin stylesheet throws a SecurityError.
How do I feature-detect a CSS feature in the browser?
Use CSS.supports() for properties — CSS.supports('anchor-name: --a') — and the selector() form for selectors, as in CSS.supports('selector(:has(a))'). At-rules are not covered by either, so test those by inserting the rule into a stylesheet and checking whether it parsed.
See what any site is really made of
Colors, type scale, spacing, breakpoints, motion and custom properties — read from the live page in one click, exported as Tailwind, CSS, SCSS, JSON or design tokens.
Add CSS DNA to Chrome — Free