Sass Nesting

Sass nesting lets you write selectors inside other selectors so your stylesheet's structure can mirror your HTML's structure.

Nesting Selectors in Sass

Instead of repeating a parent selector for every child rule, Sass lets you nest child selectors directly inside the parent's block. The compiler flattens this nesting back out into the descendant selectors that plain CSS requires.

Basic Nesting

<!DOCTYPE html>
<html>
<head>
<style id="compiled-css"></style>
</head>
<body>
<nav class="site-nav"><ul><li><a href="#">Home</a></li><li><a href="#">About</a></li></ul></nav>

<script src="https://cdn.jsdelivr.net/npm/sass.js@0.11.1/dist/sass.sync.js"></script>
<script>
  Sass.setWorkerUrl('https://cdn.jsdelivr.net/npm/sass.js@0.11.1/dist/sass.worker.js');
  var sass = new Sass();
  var scss = ".site-nav {\n  background: #222;\n\n  ul {\n    list-style: none;\n    margin: 0;\n  }\n\n  li {\n    display: inline-block;\n  }\n\n  a {\n    color: white;\n    text-decoration: none;\n  }\n}";
  sass.compile(scss, function (result) {
    if (result && typeof result.text === "string") {
      document.getElementById("compiled-css").textContent = result.text;
    } else {
      var msg = (result && (result.formatted || result.message)) || "Unknown Sass compile error";
      var pre = document.createElement("pre");
      pre.style.color = "#b00020";
      pre.style.whiteSpace = "pre-wrap";
      pre.style.fontFamily = "monospace";
      pre.style.padding = "16px";
      pre.textContent = "Sass compile error:\n" + msg;
      document.body.prepend(pre);
    }
  });
</script>
</body>
</html>

The Parent Selector (&)

Inside a nested block, the ampersand (&) refers back to the parent selector. It is most useful for pseudo-classes, pseudo-elements, and state classes, where there must be no space between the parent and the suffix in the compiled CSS.

Using & for Pseudo-Classes and States

<!DOCTYPE html>
<html>
<head>
<style id="compiled-css"></style>
</head>
<body>
<button class="btn">Click me</button>
<button class="btn is-active">Active</button>

<script src="https://cdn.jsdelivr.net/npm/sass.js@0.11.1/dist/sass.sync.js"></script>
<script>
  Sass.setWorkerUrl('https://cdn.jsdelivr.net/npm/sass.js@0.11.1/dist/sass.worker.js');
  var sass = new Sass();
  var scss = ".btn {\n  background: #444;\n  color: white;\n\n  &:hover {\n    background: #666;\n  }\n\n  &:focus {\n    outline: 2px solid #9cf;\n  }\n\n  &.is-active {\n    background: #0a7;\n  }\n}";
  sass.compile(scss, function (result) {
    if (result && typeof result.text === "string") {
      document.getElementById("compiled-css").textContent = result.text;
    } else {
      var msg = (result && (result.formatted || result.message)) || "Unknown Sass compile error";
      var pre = document.createElement("pre");
      pre.style.color = "#b00020";
      pre.style.whiteSpace = "pre-wrap";
      pre.style.fontFamily = "monospace";
      pre.style.padding = "16px";
      pre.textContent = "Sass compile error:\n" + msg;
      document.body.prepend(pre);
    }
  });
</script>
</body>
</html>

& for BEM-Style Naming

Combining & with a suffix lets you generate compound class names without retyping the block name. This pairs naturally with BEM-style conventions, where &__element and &--modifier expand to .card__element and .card--highlighted.

& With Suffixes for BEM

<!DOCTYPE html>
<html>
<head>
<style id="compiled-css"></style>
</head>
<body>
<div class="card"><div class="card__title">Title</div><div class="card__body">Body text</div></div>
<div class="card card--highlighted"><div class="card__title">Highlighted</div></div>

<script src="https://cdn.jsdelivr.net/npm/sass.js@0.11.1/dist/sass.sync.js"></script>
<script>
  Sass.setWorkerUrl('https://cdn.jsdelivr.net/npm/sass.js@0.11.1/dist/sass.worker.js');
  var sass = new Sass();
  var scss = ".card {\n  padding: 16px;\n\n  &__title {\n    font-size: 1.25rem;\n  }\n\n  &__body {\n    color: #555;\n  }\n\n  &--highlighted {\n    border: 1px solid gold;\n  }\n}";
  sass.compile(scss, function (result) {
    if (result && typeof result.text === "string") {
      document.getElementById("compiled-css").textContent = result.text;
    } else {
      var msg = (result && (result.formatted || result.message)) || "Unknown Sass compile error";
      var pre = document.createElement("pre");
      pre.style.color = "#b00020";
      pre.style.whiteSpace = "pre-wrap";
      pre.style.fontFamily = "monospace";
      pre.style.padding = "16px";
      pre.textContent = "Sass compile error:\n" + msg;
      document.body.prepend(pre);
    }
  });
</script>
</body>
</html>
  • Keep nesting to about three or four levels deep at most
  • Nest to express a real relationship, not just to save keystrokes
  • Use & for pseudo-classes, pseudo-elements, and state or modifier classes
  • Avoid nesting purely to visually group unrelated rules
  • Remember that every level of nesting raises the specificity of the compiled selector
Note: Excessive nesting produces long, highly specific compiled selectors, such as .page .sidebar .widget .widget-title span. Deeply nested output is harder to override later and can make the compiled CSS noticeably larger.
Note: A useful rule of thumb: if you can't describe why one selector is nested inside another in a single sentence about the DOM relationship, it's probably a candidate for flattening.
PatternExampleCompiles To
Descendant nesting.card { .title { } }.card .title { }
State with &.btn { &:hover { } }.btn:hover { }
Modifier with &.card { &--large { } }.card--large { }
Nested media query.box { @media (min-width: 600px) { } }@media (min-width: 600px) { .box { } }
Note: Media queries can be nested inside a selector too. Sass hoists the selector's declarations inside the @media block automatically, which keeps a component's responsive rules physically close to its base styles.

Exercise: Sass Nesting

What is the main benefit of nesting selectors in Sass?