W3C home > Mailing lists > Public > public-css-archive@w3.org > December 2020

[csswg-drafts] [css-scoping] Proposal for light-dom scoping/namespacing with re-designed `@scope` rule (#5809)

From: Miriam Suzanne via GitHub <sysbot+gh@w3.org>
Date: Fri, 18 Dec 2020 20:39:09 +0000
To: public-css-archive@w3.org
Message-ID: <issues.opened-771156341-1608323948-sysbot+gh@w3.org>
mirisuzanne has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-scoping] Proposal for light-dom scoping/namespacing with re-designed `@scope` rule ==
This would likely require additions to both [CSS Scoping](https://drafts.csswg.org/css-scoping/) and [CSS Cascade](https://drafts.csswg.org/css-cascade/). See my [full explainer](https://github.com/oddbird/css-sandbox/blob/main/src/scope/explainer.md) for more details.

As I've been working on proposals around cascade layers & component queries, there is another aspect of "cascade modernization that comes up regularly: scope. I'm aware that there is some hesitancy on the issue, since the [initial specification][] was never implemented, and Shadow DOM was seen as a path forward (potentially a replacement). I think that time (and further development of Shadow-DOM) has helped clarify two quite different use-cases:

1. Total isolation of a DOM subtree/fragment from the host page, so that no selectors get in or out unless explicitly requested.
2. Lighter-touch component namespacing, and prioritization of "proximity" when resolving the cascade.

Shadow-DOM addresses the first, but it comes with a lot of overhead that is required for "full isolation". Meanwhile authors rely on convoluted naming conventions (like [BEM][]) and JS tooling (such as [CSS Modules][], [Styled Components][], & [Vue Scoped Styles][]) for the second use-case… which has been thoroughly discussed in various forms:

- [Bring Back Scope](https://github.com/w3c/csswg-drafts/issues/3547)
- [Selector Boundaries](https://github.com/w3c/csswg-drafts/issues/5057)
- [CSS Namespaces](https://github.com/w3c/csswg-drafts/issues/270)
 
[initial specification]: https://www.w3.org/TR/css-scoping-1/
[BEM]: http://getbem.com/
[CSS Modules]: https://github.com/css-modules/css-modules
[Styled Components]: https://styled-components.com/
[Vue Scoped Styles]: https://vue-loader.vuejs.org/guide/scoped-css.html

## Re-introducing `@scope <selector> { ... }` with a few adjustments…

### 1. Provide a "lower boundary" or "slot" syntax 

This would make it possible to scope fragments rather than entire DOM sub-trees. @giuseppeg [has suggested a syntax](https://github.com/w3c/csswg-drafts/issues/3547#issuecomment-524206816) that I think is a good starting-point for more bikeshed discussion:

```css
@scope (from: .carousel) and (to: .carousel-slide-content) {
  p { color: red }
}
```

In my mind, only the first ("from") clause should be required, and may not need explicit labeling. It would likely accept a single (complex) selector:

```css
@scope (.media-block) {
  img { border-radius: 50%; }
}
```

In terms of selector-matching, this would be the same as `.media-block img`, but with slightly different cascade implications (see below). The second ("to") clause would be optional, and accept a list of selectors that represent lower-boundary "slots" in the scope. The targeted lower-boundary elements are included in the scope, but their descendants are not:

```css
@scope (.media-block) to (.content) {
  img { border-radius: 50%; }
  .content { padding: 1em; }
}
```

Which would only match `img` and `.content` inside `.media-block` -- _but not if there is no intervening `.content` between the scope root and selector target_. This follows the current selector-scoping behavior of various popular tools.

I'm not convinced that `to` is necessarily the right keyword (others have proposed `until`) or if we should even consider using a functional syntax, or calling calling the lower boundary "slots":

```css
@scope root(.media-block) slots(.content) { /* ... */ }
```

More discussion would be useful.

### 2. Make the cascade effects of scoping much less intrusive (weighted below specificity)

When scopes do overlap, it's useful to recognize the _proximity_ of a scope (inner scope takes precedence) in the cascade. This is not currently represented in CSS. Descendant selectors rely on source order rather than proximity:

```css
/* link colors for light and dark backgrounds */
.light-theme a { color: purple; }
.dark-theme a { color: plum; }
```

When these color themes are nested, the dark theme will always take precedence:

```html
<div class="dark-theme">
  <a href="#">plum</a>

  <div class="light-theme">
    <a href="#">also plum???</a>
  </div>
</div>
```

Both shadow DOM and the original spec give scoped context a very powerful impact on the cascade — overriding even specificity. The original spec also inverted scope-layering for `!important` declarations. This follows the logic of more highly-isolated use-cases, where there is more clear distinction between the inner scope and the outer host. But in the more common lightly-scoped cases, a more nuanced interplay between specificity and scope is helpful. Most existing tools only add minimal cascade weight to scoped selectors, like a single attribute selector.

I propose re-adding "scope proximity" to the cascade specification _after/below_ selector specificity, but above/before source-order. That would help resolve our example above:

```css
@scope (.light-theme) {
  a { color: purple; }
}

@scope (.dark-theme) {
  a { color: plum; }
}
```

```html
<div class="dark-theme">
  <a href="#">plum</a>

  <div class="light-theme">
    <a href="#">purple</a>
  </div>
</div>
```

While still allowing more _specific_ selectors to override scope when desired.

If authors desire more layering impact similar to the initial spec, that is now available using [Cascade Layers](https://drafts.csswg.org/css-cascade-5/#layering) — and the two features can be combined.

## A path forward

This still needs a lot of work, but my goal here is to open discussion around a path forward for light-DOM scope/namespacing. I have a much more detailed [explainer](https://github.com/oddbird/css-sandbox/blob/main/src/scope/explainer.md) for my thought-process — but there are a lot of open questions, and I'd like to: 

- gauge CSSWG interest before going deeper
- get more people involved with fleshing out the details

Happy for comments, thanks!

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/5809 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Friday, 18 December 2020 20:39:11 UTC

This archive was generated by hypermail 2.4.0 : Tuesday, 5 July 2022 06:42:24 UTC