What Happens When You Omit the Ampersand in CSS Nesting

In native CSS nesting, omitting the ampersand (&) causes the browser to treat the nested rule as an implicit descendant selector by automatically prepending an ampersand followed by a space (&). While this makes nesting straightforward for child elements and descendant classes, it completely changes how pseudo-classes, pseudo-elements, and compound selectors evaluate. Understanding this automatic behavior is essential for avoiding subtle layout and styling bugs when writing modern, preprocessor-free CSS.

The Default Behavior: Implicit Descendant Combinator

When you omit the & selector inside a nested block, modern CSS interprets the nested selector as if you had written & [selector] with a whitespace descendant combinator.

Consider the following CSS:

.card {
  color: black;

  .title {
    font-weight: bold;
  }
}

Because the & is omitted before .title, the browser evaluates it as:

.card .title {
  font-weight: bold;
}

This applies to element selectors as well, thanks to the CSS Nesting specification updates (often referred to as relaxed nesting):

.card {
  p {
    line-height: 1.5;
  }
}

This compiles conceptually to .card p, matching any <p> tag that is a descendant of .card.

The Pseudo-Class Pitfall

The most common issue when omitting the ampersand occurs with pseudo-classes such as :hover, :focus, or :nth-child.

Developers often write:

.button {
  background-color: blue;

  :hover {
    background-color: darkblue;
  }
}

Because the & was omitted, the browser treats :hover as a descendant selector:

.button :hover {
  background-color: darkblue;
}

Instead of styling the .button when it is hovered, this rule styles any descendant element inside the button (such as an icon or <span>) when that child is hovered.

To apply the state to the parent element itself, you must explicitly include the & without a space:

.button {
  &:hover {
    background-color: darkblue;
  }
}

Compound Selectors Require the Ampersand

Omitting the & prevents you from creating compound selectors that target the same element with multiple classes or attributes.

If you write:

.alert {
  .warning {
    border-color: orange;
  }
}

The browser evaluates this as .alert .warning (a .warning element nested inside an .alert element).

If the goal is to style an element that carries both classes simultaneously (<div class="alert warning">), omitting the ampersand fails. You must explicitly attach the class directly to the ampersand:

.alert {
  &.warning {
    border-color: orange;
  }
}

Modifying Ancestors (:has and Reverse Contexts)

Omitting the & always nests downward into descendants. You cannot apply styles conditionally based on an ancestor or modify an outer context without explicitly placing the &:

.item {
  /* Fails: Interpreted as `.item html[dir="rtl"]` */
  html[dir="rtl"] {
    margin-right: 0;
  }

  /* Works: Interpreted as `html[dir="rtl"] .item` */
  html[dir="rtl"] & {
    margin-right: 0;
  }
}

Quick Reference Summary

  • Without & (.parent { .child {} }): Evaluates to .parent .child (Descendant selector).
  • With & followed by a space (.parent { & .child {} }): Identical to omitting &.
  • With & directly attached (.parent { &:hover {} }): Evaluates to .parent:hover (Same-element modification).
  • With & directly attached to a class (.parent { &.active {} }): Evaluates to .parent.active (Compound selector).