CSS @scope At-Rule

The CSS @scope at-rule limits style rules to a specific part of the document. It helps you build components without long selectors, repeated class prefixes, or styles that accidentally affect content outside the component.

CSS scope became newly available across current browser versions in 2026. Older browsers may ignore scoped blocks, so add sensible base styles before using @scope when broad compatibility is required.

Why Use CSS Scope?

Large stylesheets often contain similar names such as .title, .button, and .message. A rule intended for one component can unintentionally change another. @scope gives the rule a clear boundary.

  • Keep component styles within a selected subtree.
  • Stop styles before they enter a nested region.
  • Reduce selector length and specificity.
  • Reuse simple class names safely in different components.

CSS @scope Syntax

A scope can have a root selector and an optional limit selector.

Syntax:

@scope (scope-root) to (scope-limit) {
  /* Scoped style rules */
}

The scope root defines where matching begins. The optional scope limit creates a lower boundary that scoped selectors cannot cross.

Create a Basic Scope

The following rule changes .title only when it appears inside .profile-card. A title elsewhere on the page keeps its normal style.

Example:

@scope (.profile-card) {
  /* This selector is limited to each profile card. */
  .title {
    color: rebeccapurple;
  }

  .role {
    color: #555;
  }
}

You do not need to repeat .profile-card before every selector. This keeps the component rules shorter and easier to update.

Use a Scope Limit

A scope limit creates a donut-shaped boundary. Rules apply inside the outer component but stop before matching nested content.

Example:

@scope (.article-card) to (.comments) {
  /* Headings in the comments section are not selected. */
  h2 {
    color: darkgreen;
  }

  a {
    text-decoration-thickness: 2px;
  }
}

This is useful when a component contains another independent component that should manage its own appearance.

Refer to the Scope Root

Use the :scope pseudo-class when you need to style the scope root itself. Inside an @scope block, :scope represents the element matched by the scope root.

Example:

@scope (.notice) {
  /* Style the notice container itself. */
  :scope {
    border-left: 4px solid royalblue;
    padding: 1rem;
  }

  :scope > .title {
    margin-top: 0;
  }
}

Understand Scope Proximity

An element can be inside more than one matching scope. When competing scoped rules have the same origin, importance, and specificity, the browser prefers the rule whose scope root is closest to the element.

Example:

@scope (.theme) {
  p { color: navy; }
}

@scope (.panel) {
  /* Wins for paragraphs closer to the .panel root. */
  p { color: darkred; }
}

Scope proximity is considered after specificity and before source order. It does not make every scoped rule automatically stronger than an unscoped rule.

Use Inline Scope

You can place a <style> element inside a component and omit the scope root. The enclosing parent becomes the scope root automatically.

Example:

<section class="team-card">
  <style>
    @scope {
      h2 { color: teal; }
      p { max-width: 45ch; }
    }
  </style>

  <h2>Support Team</h2>
  <p>This paragraph receives the scoped styles.</p>
</section>

Tip: Keep shared production styles in maintainable stylesheets. Inline scope is most useful for self-contained examples, generated components, or server-rendered fragments.

Complete Runnable Example

The page heading and product heading use the same class. Only the heading inside the product card receives the scoped color.

Example:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>CSS Scope Example</title>
  <style>
    body { font-family: Arial, sans-serif; }
    .product-card { border: 1px solid #bbb; padding: 1rem; margin: 1rem 0; }
    .title { color: #333; }

    /* Only titles inside product cards receive this style. */
    @scope (.product-card) {
      .title { color: #0b57d0; }
      .price { font-weight: 700; }
      button { background: #0b57d0; color: white; padding: .5rem 1rem; border: 0; }
    }
  </style>
</head>
<body>
  <h2 class="title">Featured Products</h2>
  <article class="product-card">
    <h2 class="title">Wireless Keyboard</h2>
    <p class="price">$49</p>
    <button>Add to Cart</button>
  </article>
</body>
</html>

Add a Fallback for Older Browsers

Place general component styles before the scoped block. Supporting browsers apply the enhanced rules, while older browsers keep the usable fallback.

Example:

/* Fallback for every browser. */
.product-card .title {
  color: #333;
}

/* Enhanced component scope in supporting browsers. */
@scope (.product-card) {
  .title {
    color: #0b57d0;
  }
}

CSS Scope Best Practices

  • Choose a stable component root instead of a deeply nested selector.
  • Add a scope limit when nested widgets must keep independent styles.
  • Use :scope only when the root itself needs styling.
  • Keep fallback rules readable rather than duplicating the entire scoped block.
  • Test specificity, proximity, and nested component behavior in supported browsers.

Conclusion

CSS @scope creates clear styling boundaries without adding Shadow DOM or complicated naming systems. Use scope roots for components, scope limits for nested regions, and base rules for older browsers. The result is a stylesheet that is easier to reuse and less likely to leak styles across the page.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram