Sass @at-root Rule

Intermediate
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
Escape nesting

What You’ll Learn

Sass @at-root moves nested styles to the document root instead of under the current selector. This page covers basic escape, selector.unify with &, (with:) / (without:) queries for @media and @supports, and five compiled examples.

01

Escape

@at-root

02

Parent

& + unify

03

Without

Drop media

04

With

Keep rules

05

All

Full bubble-up

06

Practice

5 examples

What Is @at-root?

Official docs: the @at-root rule is usually written @at-root { … } and causes everything within it to be emitted at the root of the document instead of using normal nesting. It is most often used for advanced nesting with the SassScript parent selector and selector functions.

  • By default it escapes style rules only.
  • @media, @supports, and similar at-rules stay unless you query them out.
  • @at-root .foo { … } is shorthand for putting one rule at the root.
  • & still contains the outer selector as an expression even inside @at-root.
💡
Beginner tip

Nesting says “put this under the parent.” @at-root says “bubble this out—I already built the full selector myself.”

📝 Syntax

styles.scss
.parent {
  color: #333;

  @at-root {
    .sibling { color: #666; }
  }

  // With a selector:
  @at-root .modal { z-index: 10; }

  // Control wrappers:
  @at-root (without: media) { … }
  @at-root (with: rule) { … }
}

Official fun fact: @at-root <selector> { … } is shorthand for @at-root { <selector> { … } }.

🧩 Why @at-root With &?

Official docs: Sass does not know what interpolation was used to generate a selector when it performs selector nesting. It will automatically add the outer selector to the inner selector even if you used & as a SassScript expression. @at-root explicitly tells Sass not to include the outer selector again (although that outer selector is still available inside &).

styles.scss
@use "sass:selector";

@mixin unify-parent($child) {
  @at-root #{selector.unify(&, $child)} {
    @content;
  }
}

⚙️ Beyond Style Rules: with / without

Official docs: control exactly what is included or excluded with syntax like media-query features:

  • @at-root (without: <rules…>) { … } — exclude listed rules.
  • @at-root (with: <rules…>) { … } — exclude everything except listed rules.
  • You can list at-rule names such as media or supports.

Special values

  • rule — means style rules. Example: (with: rule) keeps nesting under the current selector but drops at-rules.
  • all — means every at-rule and style rule should be excluded (full bubble to the document root).

⚡ Quick Reference

GoalCode
Escape style nesting@at-root { .x { … } }
One selector at root@at-root .modal { … }
Built selector + &@at-root #{selector.unify(&, $child)} { … }
Leave @media@at-root (without: media) { … }
Keep style rule only@at-root (with: rule) { … }
Escape everything@at-root (without: all) { … }

Examples Gallery

Each example shows how nesting changes in the compiled CSS. Open View Compiled CSS for verified output.

📚 Getting Started

Escape nesting when you build the full selector yourself.

Example 1 — selector.unify + &

Combine the parent selector with an element type without double-nesting.

styles.scss
@use "sass:selector";

@mixin unify-parent($child) {
  @at-root #{selector.unify(&, $child)} {
    @content;
  }
}

.wrapper .field {
  @include unify-parent("input") {
    border: 1px solid #ccc;
  }
  @include unify-parent("select") {
    background: #f5f5f5;
  }
}

How It Works

selector.unify(&, "input") builds .wrapper input.field. Without @at-root, Sass would nest that under .wrapper .field again and produce a broken selector.

Example 2 — Basic Root Escape

Emit sibling selectors at the document root while keeping other nested rules.

styles.scss
.parent {
  color: #333;

  @at-root {
    .sibling {
      color: #666;
    }

    .orphan {
      color: #999;
    }
  }

  .nested {
    font-weight: bold;
  }
}

How It Works

.sibling and .orphan leave .parent. .nested still compiles as .parent .nested.

📈 Media, Supports & Full Escape

Control which wrappers stay around your styles.

Example 3 — without: media / with: rule

Official-style control inside a print media query.

styles.scss
@media print {
  .page {
    width: 8in;

    @at-root (without: media) {
      color: #111;
    }

    @at-root (with: rule) {
      font-size: 1.2em;
    }
  }
}

How It Works

Both queries drop @media print but keep the .page style rule. width stays inside the media query as normal nesting.

Example 4 — Escape @supports

Leave a feature query while keeping or adjusting style nesting.

styles.scss
@supports (display: grid) {
  .layout {
    display: grid;

    @at-root (without: supports) {
      .no-grid-fallback {
        display: block;
      }
    }

    @at-root (with: rule) {
      gap: 1rem;
    }
  }
}

How It Works

(without: supports) removes the feature query but keeps .layout nesting for the fallback. (with: rule) keeps .layout for gap and drops @supports.

Example 5 — without: all vs Plain @at-root

Compare full escape with escaping only the style-rule parent.

styles.scss
@media screen {
  .card {
    padding: 1rem;

    @at-root (without: all) {
      .toast {
        position: fixed;
        bottom: 1rem;
      }
    }

    @at-root .modal {
      z-index: 10;
    }
  }
}

How It Works

(without: all) bubbles .toast all the way out. Plain @at-root .modal leaves @media but escapes .card nesting.

🚀 Real-World Use Cases

  • Selector libraries — mixins that unify & with element/type selectors.
  • BEM helpers — emit modifiers or elements at a controlled root.
  • Print / screen splits — share a nested block but print some rules outside @media.
  • Feature-query fallbacks — keep structure while dropping @supports.
  • Global UI chrome — toasts/modals that should not inherit a card selector.

🧠 How Compilation Works

1

Nest as usual

You write styles under a parent selector or at-rule.

Source
2

Hit @at-root

Optional with / without queries choose what to strip.

Escape
3

Bubble selectors

Sass emits the block outside the excluded wrappers.

Resolve
4

CSS ships

Root-level (or partially escaped) rules appear in the output.

⚠️ Common Pitfalls

  • Forgetting @at-root with interpolated & — Sass may nest again and break the selector.
  • Expecting media to vanish — plain @at-root keeps @media.
  • Overusing (without: all) — easy to lose intentional nesting and cascade context.
  • Confusing & availability — outer selectors remain in & even inside @at-root.
  • Using it for everything — most nesting does not need @at-root; reserve it for advanced cases.

💡 Best Practices

✅ Do

  • Use @at-root when you build the full selector with &
  • Prefer selector.unify for combining parents and children
  • Name queries clearly: (without: media), (with: rule)
  • Keep escapes local inside mixins that own the selector logic
  • Compare CSS output when unsure what still wraps the rule

❌ Don’t

  • Reach for @at-root instead of simple nesting
  • Assume style-rule escape also drops @media
  • Bubble global chrome with (without: all) without checking cascade
  • Double-nest manually after already unifying selectors
  • Hide complex selector bugs behind more nesting

Key Takeaways

Knowledge Unlocked

Five things to remember about Sass @at-root

Bubble nested styles out—and control which wrappers stay.

5
Core concepts
🧩 02

Unify

& + selectors

Advanced
🔀 03

Without

drop media…

Query
📄 04

With rule

keep nesting

Style
05

All

full bubble-up

Power

❓ Frequently Asked Questions

It causes everything inside it to be emitted at the root of the document instead of using normal nesting under the current selector.
Most often with advanced nesting: when you build a selector with & and selector functions (like selector.unify), Sass would still nest the outer selector unless you use @at-root.
No. On its own, @at-root only escapes style-rule nesting. At-rules like @media and @supports stay unless you use (without: …) or (with: …) queries.
It tells Sass to exclude @media wrappers so the nested styles compile outside the media query while still respecting other nesting rules you keep.
rule is a special value meaning style rules. @at-root (with: rule) excludes all at-rules but preserves style-rule nesting.
all means every at-rule and style rule should be excluded, so the contents bubble all the way to the document root.
Did you know?

Official Sass docs note that even inside @at-root, the outer selector is still included in & as an expression—so you can rebuild a smarter selector without Sass nesting it a second time.

Conclusion

@at-root is the escape hatch for advanced nesting: emit styles at the document root, rebuild selectors with &, and fine-tune which at-rules stay with with / without queries. Use it when normal nesting would fight the selector you already built.

Continue with @if or @mixin / @include.

Next: Sass @if

Write compile-time conditionals for optional styles and feature flags.

@if rule →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful