without Sass, without PostCSS, directly in the browser
CSS Nesting is natively available in all modern browsers in 2026. The & selector, nested media queries, and at-rules like @layer and @supports inside rule blocks make preprocessors unnecessary for many projects. What once required Sass, Less, or PostCSS now works directly in the browser, with no build step, no source maps, and no dependencies.
Table of Contents
- 1. Why native CSS Nesting is a turning point
- 2. The & selector: meaning and mechanism
- 3. Implicit nesting: & as an optional element
- 4. Nested @media and @supports queries
- 5. Specificity in CSS Nesting: what changes
- 6. Sass migration: what works 1:1 and what does not
- 7. CSS Nesting with @layer and @scope
- 8. Practical patterns: BEM, modifiers, and states
- 9. CSS Nesting versus Sass, a direct comparison
- 10. Summary
- 11. FAQ
1. Why native CSS Nesting is a turning point
Since the early days of Sass and Less, CSS Nesting has been the most popular feature of CSS preprocessors. Being able to write rules for child elements inside their parent element reduces repetition, improves readability, and makes the relationship between a selector and its context explicit. For years this feature was only accessible through a build step: Sass, Less, or PostCSS files had to be compiled before the browser could process them. With the introduction of native CSS Nesting in every modern browser engine, that build step is no longer necessary for many use cases.
Of course, that does not mean Sass becomes obsolete overnight. Sass also offers variables (now largely taken over by custom properties), functions, mixins, and complex logic that do not exist in native CSS. But the main reason many projects reached for Sass in the first place, namely CSS Nesting, is achievable with native CSS in 2026. Anyone starting a new project today can often skip a CSS preprocessor entirely. That simplifies the build setup, reduces dependencies, and eliminates a whole class of source map problems when debugging in the browser DevTools.
2. The & selector: meaning and mechanism
The & selector is the heart of CSS Nesting. It stands for the selector of the enclosing rule block and lets you define modifiers, pseudo-classes, and pseudo-elements directly inside the parent block. This behavior was well known in Sass: .button { &:hover { } } compiled to .button:hover { }. In native CSS Nesting the behavior is identical: the browser performs the selector concatenation internally, with no build step required.
The & selector can appear at any position in a nested selector, not only at the start. .child { .parent & { color: red; } } produces .parent .child { color: red; }, a context modification where the element is only styled inside a specific parent context. This is especially useful for theme variants: a dark container can recolor child elements through .dark-theme & { } inside the child selector block, without having to write the selector twice. This flexibility of & in CSS Nesting even goes beyond what Sass offers by default in some respects.
/* Native CSS Nesting: no preprocessor required */
.card {
background: white;
border-radius: 0.75rem;
padding: 1.5rem;
/* & = .card, pseudo-class nesting */
&:hover {
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
transform: translateY(-2px);
}
/* & = .card, modifier class nesting */
&.card--featured {
border: 2px solid #7c3aed;
}
/* Descendant nesting */
.card__title {
font-size: 1.25rem;
font-weight: 700;
}
/* & in non-initial position: context modifier */
.dark-theme & {
background: #1e1b4b;
color: white;
}
/* Pseudo-element nesting */
&::before {
content: '';
display: block;
height: 4px;
background: linear-gradient(90deg, #7c3aed, #c4b5fd);
border-radius: 4px 4px 0 0;
}
}
3. Implicit nesting: & as an optional element
Since the revision of the CSS Nesting specification (relaxed nesting), the & selector is no longer required for element selectors, class selectors, and ID selectors when the nested selector can be unambiguously recognized as a child element. That means .parent { .child { } } is equivalent to .parent { & .child { } }: the browser adds the & implicitly. This significantly simplifies migrating Sass code, since many Sass files use nested selectors without an explicit &.
It is important to understand that implicit CSS Nesting without & only works for simple selectors that begin with a tag, a class, or an ID. Pseudo-classes and pseudo-elements still require the explicit &. More complex selectors such as :is(), :not(), and combinator selectors also need the & for clear semantics. The rule of thumb for well maintained CSS Nesting: whenever you are directly modifying the parent selector (pseudo-classes, pseudo-elements, modifier classes), write & explicitly. For genuine child elements, the & can be omitted, but consistency within a project matters more than omitting a few characters.
4. Nested @media and @supports queries
The most powerful feature of native CSS Nesting is the ability to nest @media, @supports, and @layer rules inside a selector block. This flips the traditional CSS structure around: instead of defining a media query globally and listing every affected selector inside it, you write the selectors with their base styles and place the responsive variations right next to them. This keeps related code together, so a property is defined in one place instead of being spread across five different media query blocks.
This inversion of structure has a considerable impact on the maintainability of large CSS codebases. When a component needs to change, all the relevant styles are in one place, so the developer no longer has to scroll through the entire file to find every media query block that touches the component. This is a key advantage of CSS Nesting over classic flat CSS that goes beyond pure syntactic nesting. Sass popularized this pattern, but native CSS Nesting makes it available without a build step.
/* Nested @media: responsive styles colocated with the component */
.hero {
font-size: 1.5rem;
padding: 2rem;
/* Responsive breakpoint, right next to the base styles */
@media (min-width: 768px) {
font-size: 2.5rem;
padding: 4rem;
}
@media (min-width: 1024px) {
font-size: 3.5rem;
padding: 6rem 4rem;
}
/* Feature detection, nested @supports */
@supports (display: grid) {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
/* Nested @layer for cascade control */
@layer components {
.button {
padding: 0.5rem 1rem;
border-radius: 0.375rem;
&:hover {
opacity: 0.9;
}
/* Layer override from within the block */
@layer overrides {
&.button--ghost {
background: transparent;
}
}
}
}
/* Container queries nested inside a selector */
.sidebar-widget {
padding: 1rem;
@container (min-width: 300px) {
padding: 1.5rem;
display: flex;
gap: 1rem;
}
}
5. Specificity in CSS Nesting: what changes
Specificity calculation in native CSS Nesting matches Sass specificity: a nested selector calculates its specificity from the concatenation of the parent selector and the nested selector. .parent .child has the same specificity whether it is written directly or produced through CSS Nesting. There is no special treatment, no increased specificity caused by the nesting itself. That is an important distinction from a common misconception: CSS Nesting does not create new specificity levels.
A subtle exception concerns the & selector combined with :is(). When & represents a list of selectors (for example through multiple selectors before the nested block), specificity is calculated according to the rules of :is(), meaning by the most specific selector in the list. This can lead to unexpected specificity differences. For well maintained CSS Nesting, it is therefore advisable to avoid selector lists before a nesting block and to prefer single selectors instead. Where selector lists are necessary, specificity should be checked deliberately.
6. Sass migration: what works 1:1 and what does not
Migrating from Sass to native CSS Nesting is straightforward for most simple nesting cases. Sass code such as .nav { .nav-item { } } works identically in native CSS. Pseudo-classes with &:hover { }, modifier classes with &.is-active { }, and pseudo-elements with &::before { } also carry over directly. That covers the bulk of everyday Sass usage in component styles.
What does not work in native CSS Nesting: Sass variables ($color: red), which are replaced by CSS custom properties (--color: red). Sass mixins (@mixin, @include), which have no native CSS equivalent and require either custom properties, CSS functions, or accepting code repetition. Sass loops (@each, @for), which are not supported in native CSS. For projects that make heavy use of mixins and loops, Sass remains the right choice. For projects that use Sass primarily for nesting and variables, migrating to native CSS Nesting plus custom properties is often possible and worthwhile.
/* BEM component with native CSS Nesting, migrated from Sass */
/* Before: Sass */
/* .nav {
&__item { color: gray; }
&__item--active { color: purple; }
&__link { &:hover { color: purple; } }
} */
/* After: native CSS Nesting */
.nav {
display: flex;
gap: 0.5rem;
/* BEM element */
.nav__item {
list-style: none;
/* BEM modifier, explicit & required */
&.nav__item--active {
font-weight: bold;
}
}
/* BEM element with state */
.nav__link {
color: #64748b;
text-decoration: none;
transition: color 0.2s;
&:hover,
&:focus-visible {
color: #7c3aed;
}
&[aria-current="page"] {
color: #4a1d96;
font-weight: 600;
}
}
/* Responsive, colocated with the component */
@media (max-width: 640px) {
flex-direction: column;
}
}
7. CSS Nesting with @layer and @scope
Native CSS Nesting reaches its full potential when combined with the newer CSS at-rules @layer and @scope. @layer defines a cascade layer with an explicitly set priority: styles in a lower layer are overridden by styles in a higher layer regardless of specificity. CSS Nesting inside @layer makes it possible to fully encapsulate component styles within their layer without leaving the selector hierarchy. The result is a CSS architecture that resolves cascade conflicts through structural layers instead of a specificity arms race with !important.
@scope is the newest addition to the CSS at-rule repertoire and limits the scope of a selector block to a specific DOM subtree. Combined with CSS Nesting, this produces genuine component styles without Shadow DOM: @scope (.card) ensures that every selector inside the block only matches elements that are descendants of a .card element. This solves the classic problem of CSS classes accidentally matching other places in the DOM when class names are reused, and it turns CSS Nesting into a fully fledged tool for component based CSS architecture.
8. Practical patterns: BEM, modifiers, and states
The most common practical pattern for CSS Nesting in component based CSS is mapping BEM structures. A BEM block becomes the outermost selector, while BEM elements (__element) and BEM modifiers (--modifier) are nested inside it. The result is noticeably more compact code than classic flat BEM CSS, where the block, elements, and modifiers are written as separate, disconnected rule blocks. The fact that all these rules belong to the same component becomes visually obvious through the nesting itself.
States such as .is-open, .is-loading, and aria attributes such as [aria-expanded="true"] are nested with the & selector right next to the component's base styles. This makes state management in CSS much clearer: instead of hunting through a long flat CSS file for the matching state selector, it sits directly next to the base styles. In day to day work with component based CSS Nesting, this means every component is a self contained block fully defined in a single rule hierarchy, with base styles, states, modifiers, and responsive variations all in one place.
| Sass pattern | Native CSS Nesting | Works 1:1? | Note |
|---|---|---|---|
&:hover { } |
&:hover { } |
Yes | Identical syntax |
.parent { .child { } } |
.parent { .child { } } |
Yes | Relaxed nesting, & implicit |
$variable: value |
--variable: value |
Equivalent | Custom properties instead of Sass vars |
@mixin / @include |
No equivalent | No | Sass remains necessary for mixins |
@media { } (nested) |
@media { } (nested) |
Yes | Fully supported |
9. CSS Nesting versus Sass, a direct comparison
The choice between native CSS Nesting and Sass is more nuanced in 2026 than it used to be. For new projects that do not need complex mixins, loops, or Sass functions, there is a strong case for native CSS Nesting: no build step, no source map issues, direct debugging in the browser, fewer dependencies, and automatically current browser support without manual prefix management. The browser DevTools show the native CSS directly, not the compiled output.
For projects that already have an established Sass architecture with mixins and utility functions, migrating in the short term rarely makes sense. Sass and native CSS Nesting can coexist without any trouble: Sass files compiled to native CSS with PostCSS even benefit when the output preserves native CSS Nesting instead of flattening it. That enables a gradual transition, where new components are written with native CSS Nesting while old Sass components remain in place until they are refactored.
/* Complete component, native CSS Nesting, no Sass */
.dropdown {
position: relative;
display: inline-block;
/* Trigger button */
.dropdown__trigger {
padding: 0.5rem 1rem;
background: #7c3aed;
color: white;
border: none;
border-radius: 0.5rem;
cursor: pointer;
&:hover { background: #6d28d9; }
&:focus-visible { outline: 2px solid #c4b5fd; }
}
/* Menu panel */
.dropdown__menu {
display: none;
position: absolute;
top: 100%;
left: 0;
background: white;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
box-shadow: 0 4px 24px rgba(0,0,0,0.12);
min-width: 200px;
z-index: 50;
}
/* Open state, parent class modifier */
&.is-open {
.dropdown__menu {
display: block;
}
.dropdown__trigger {
background: #4a1d96;
}
}
/* Responsive: fullscreen on mobile */
@media (max-width: 640px) {
.dropdown__menu {
position: fixed;
inset: 0;
border-radius: 0;
}
}
}
Mironsoft
CSS architecture, Sass migration, and modern build pipelines
Migrating from Sass to native CSS? We guide the transition.
We analyze your Sass architecture, identify migration potential, and develop a staged transition to native CSS Nesting, custom properties, and modern CSS at-rules, without production risk.
CSS audit
Analysis of your Sass base for migration potential and complexity drivers
Migration
Staged switch to native CSS Nesting and custom properties
Architecture
@layer, @scope, and native nesting as a sustainable CSS foundation
10. Summary
Native CSS Nesting is fully supported in every modern browser in 2026 and makes a CSS preprocessor unnecessary for many projects. The & selector enables pseudo-classes, pseudo-elements, and modifier classes directly inside the parent block. Relaxed nesting allows omitting the & for simple child element selectors. Nested @media, @supports, and @layer rules keep responsive styles and feature detections together with the component's base styles.
Migrating from Sass to native CSS Nesting is possible 1:1 for the majority of nesting usage. Sass variables are replaced by custom properties, and mixins remain the only significant feature without a native CSS equivalent. For new projects, native CSS Nesting with @layer as the CSS architecture foundation is recommended: fewer dependencies, simpler debugging, and future proof standards.
CSS Nesting: the essentials at a glance
& selector
Represents the parent selector. Usable at any position in the selector. Pseudo-classes and pseudo-elements always require an explicit &.
Nested at-rules
@media, @supports, and @layer directly inside selector blocks: colocated styles for better maintainability.
Sass migration
Nesting and pseudo-classes transfer 1:1. Sass variables become custom properties. Mixins have no native equivalent.
Browser support 2026
Chrome 112+, Firefox 117+, Safari 16.5+. Relaxed nesting (without &) from Chrome 120+. No build step needed for modern projects.