CSS Nesting: Compound vs Descendant Selectors

Native CSS nesting uses the nesting selector (&) to reference the parent rule, allowing developers to write more modular and readable stylesheets. The key distinction between &.active and & .active comes down to whitespace: omitting the space creates a compound selector that targets the parent element itself when it possesses an additional class, whereas including a space creates a descendant selector that targets a child element nested inside the parent.

The Role of the Nesting Selector (&)

In native CSS nesting, the ampersand (&) represents the parent selector list wrapped inside an :is() pseudo-class. When you nest rules, the position of & relative to other selectors determines how the final rule is resolved by the browser's CSS engine.

Compound Selectors: &.active

When there is no space between the ampersand and the class name, CSS treats the expression as a compound selector. This combines the parent selector and the new class on the same HTML element.

.button {
  background-color: blue;

  &.active {
    background-color: green;
  }
}

This compiles conceptually to:

.button.active {
  background-color: green;
}

Under the CSS Nesting specification, the browser evaluates this as :is(.button).active. It targets an element that matches both .button and .active simultaneously:

<!-- Matches &.active -->
<button class="button active">Click Me</button>

Descendant Selectors: & .active

When a space is placed between the ampersand and the class name, the whitespace acts as the descendant combinator. This specifies that the rule should apply to an element with the class .active that is located anywhere inside the parent element.

.button {
  background-color: blue;

  & .active {
    color: yellow;
  }
}

This compiles conceptually to:

.button .active {
  color: yellow;
}

The browser evaluates this as :is(.button) .active. It targets a nested descendant element rather than the parent element itself:

<!-- The outer button matches .button; the inner span matches & .active -->
<button class="button">
  Status: <span class="active">Online</span>
</button>

Summary of Differences

  • &.active (No space): Modifies the parent element. Use this for state classes, theme variations, or conditional styles applied directly to the container (e.g., .card.active, .nav-item.active).
  • & .active (With space): Traverses the DOM tree to target children. Use this when the active state belongs to an inner element contained within the parent component (e.g., an active icon, indicator, or label inside a button).