[csswg-drafts] [css-scoping] Scoping of functions, other name-defining at-rules and custom idents (#11798)

kizu has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-scoping] Scoping of functions, other name-defining at-rules and custom idents ==
## Context

There are many name-defining at-rules in CSS.

Examples: `@keyframes`, `@property`, `@counter-style`, `@position-try`, and, soon, `@function`, etc.

There are also many custom idents, regular or dashed.

Examples: custom properties, counters, anchors, timelines, etc.

A common problem for them all: currently, most of them (all? I did not check) are [_tree-scoped_](https://drafts.csswg.org/css-scoping-1/#css-tree-scoped-name).


## Problem

Current [“CSS Scoping Module Level 1”](https://drafts.csswg.org/css-scoping-1/) defines how things are scoped in Shadow DOM vs Light DOM.

However, when we're purely in a Light DOM context (or inside a single shadow root), all the custom idents exist in a single global scope. This means that it is very easy to have a name clash between libraries, components, and other CSS things, where it is very easy to accidentally reuse the same name.

The definition that wins in the cascade will be used, and it is relatively easy to break something with it. Custom property can be registered with an incorrect type, an animation could use an incorrect set of keyframes, anchored element will be attached to something unexpected, and custom functions could result in a lot of IACVT.

Authors have to use naming conventions that help reduce clashes, or external libraries like CSS Modules that guarantee the uniqueness of all these idents.

A convention is brittle and results in lengthy idents, and anything that fails to follow it could lead to an issue. External tools are, well, external.

Native CSS, by itself (without Shadow DOM), does not provide a mechanism like this.

## Proposal

When I think about what we _need_: we need proper and explicit scoping in the light DOM for all these idents and definitions.

What if we reused [`@scope`](https://drafts.csswg.org/css-cascade-6/#scoped-styles)?

Even though it did not yet ship in Firefox, I don't think it is a good idea to change its behavior today, as it was for a long time in Chrome and Safari. We don't want to break backwards compatibility. Add to this — not always you _want_ to scope all the idents, so it might be inconvenient for simple projects to have `@scope` with this strong scoping as the default behavior.

What I suggest: adding some kind of a keyword when we define an `@scope`. Name TBD and requires bikeshedding, but something like `@scope namespace (.foo) {}` (this is similar to adding an `isolated` keyword in github.com/w3c/csswg-drafts/issues/11002 — but I don't see what I propose in this issue as isolation, but more of an extension of a cascade for the custom idents).

When you then define any idents inside — they will be _scoped_ to this particular scope.

Meaning: when we use some ident on an element, we will find the closest scoping rule to this element, and use the named ident that is defined in that scope. If not found, we will go up the scope, and so forth until we will reach the global scope (what we have now without scopes at all).

```CSS
@scope namespace (.foo) {
 @function --foo() { result: lightgreen }
}
@scope namespace (.bar) {
 @function --foo() { result: pink }
}

.foo {
 background: --foo();
}

.bar {
 background: --foo();
}
```

```HTML
<div class="foo">
 should be lightgreen
</div>

<div class="bar">
 should be pink
</div>

<div class="bar">
 <div class="foo">
  should be lightgreen
 </div>
</div>


<div class="foo">
 <div class="bar">
  should be pink
 </div>
</div>

<div class="foo bar">
 should be pink (when multiple match, the one that wins in the cascade wins; in this case — one that defined later)
</div>
```

This can be seen a bit similar to how container queries, or container query length units work: by default we will look at the closest container. But we also have named containers that allow us to choose which one to use if multiple of them match.

Scopes cannot be _named_ just yet, but there is a proposal to do so: https://github.com/w3c/csswg-drafts/issues/9742

With an ability to name scopes, we could expand this feature, and allow to somehow override from which scope we want to use an ident. Maybe something like a `from-scope(<scope-name>, <ident>)`? One problem could be custom properties — not for their usage (`var(from-scope(--outer, --foo))` could potentially work), but for _definition_: it might be tricky to find a good syntax for defining a custom property _for_ a certain scope.

This can be a bit similar to the https://github.com/w3c/csswg-drafts/issues/10808 — an ability to break encapsulation from inside Shadow DOM for idents.

That's it for now. This is not a very concrete proposal, but something I was thinking about for a very long time, and something I saw others have issues as well.

Possibly, there were already issues about something like this, and this is a duplicate: if so, point me to them, and it would be great to pick this up again.

In general, I think `@scope` is the best place for something like this, with its proximity rules, and, literally, with its name.


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


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Thursday, 27 February 2025 22:02:34 UTC