Skip to content
AgileLogics
6 min read

Scoping Styles

Prerequisites: Cascade layers

Global CSS means any rule can affect any element. Several techniques scope styles to part of the page.

@scope

@scope (.card) to (.card-content) {
  :scope { border: 1px solid #ddd; }
  img { border-radius: 8px; }
  a { color: inherit; }
}
  • Rules apply only to elements inside .card — the scope root (:scope selects the root itself).
  • to (.card-content) sets a lower boundary: elements inside .card-content aren't affected. This is "donut scope" — style a component's frame without touching the content slotted inside it.
  • Selectors inside keep low specificity (img stays 0,0,1).

Scope proximity

When two scoped rules conflict with equal specificity, the one whose scope root is closer in the DOM wins — before source order is considered:

<style>
  @scope (.light) { p { color: rgb(0, 0, 0); } }
  @scope (.dark) { p { color: rgb(255, 255, 255); } }
</style>
<div class="dark">
  <div class="light"><p id="inner">Inner</p></div>
  <p id="outer">Outer</p>
</div>
<script>
  for (const id of ["inner", "outer"]) {
    console.log(id, getComputedStyle(document.getElementById(id)).color);
  }
</script>
inner rgb(0, 0, 0)
outer rgb(255, 255, 255)

The inner paragraph is black although the .dark rule comes later: the .light root is nearer. With plain descendant selectors (.dark p vs .light p), source order would have made it white.

@scope works in all major browsers (Chrome and Edge 118, Safari 17.4, Firefox 146).

Other scoping techniques

Technique How it scopes
Naming conventions (BEM) Unique class names by convention (next lessons)
CSS Modules The build tool rewrites class names to be unique per file
Framework scoped styles Vue <style scoped>, Svelte, Angular add attributes to selectors
Shadow DOM True encapsulation for web components — outside styles don't match inside
Utility classes Styles live on the element, so nothing leaks

Styling inside shadow DOM

From inside a component, :host, :host(.variant), and ::slotted() style the host and slotted children. From outside, ::part(name) and custom properties are the only ways in — design components to expose tokens like --button-bg for theming. See the HTML course's web components lessons.