[csswg-drafts] [css-scoping] Handling global name-defining constructs in shadow trees

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

== [css-scoping] Handling global name-defining constructs in shadow trees ==
Since the introduction of Shadow DOM, we've been struggling with what to do with name-defining things, like @font-face, which define global names for other things to reference.

* Can @font-face be used in shadow trees?
* Does it still define a global name? What's our plan to deal with collisions between non-communicating components?
* Does it define a scoped name? What's our plan to deal with collisions between an outer and inner @font-face name, when the font-family property inherits across a boundary?

Right now the answer is a collective shrug. I think I have an answer, however:

1. Every name-defining thing (such as `@font-face`) is valid inside of shadow trees, and is scoped to the TreeScope that its defining stylesheet is in. It's implicitly available in nested TreeScopes, but can be shadowed.
2. Every reference to a defined name (such as a `font-family` font name) is implicitly a tuple of (name, defining scope), where the defining scope is the TreeScope the reference's stylesheet is in.
3. You can explicitly alter the scope of a reference with a `scoped(val, <integer> | global)` function, where the `<integer>` says how many TreeScopes upward you should walk before resolving the name.

---

This has some implications. Since the defining scope is implicitly captured by a reference, it doesn't change as the value inherits. Thus, in this situation:

```html
<style>
@font-face { font-family: foo; ... }
body { font-family: foo; }
x-component::part(my-p) { font-family: foo; }
</style>
<body>
 <p>ONE
 <my-component>
  <::shadow>
    <style>
    @font-face { font-family: foo; ... }
    p.foo { font-family: foo; }
    p.bar { font-family: scoped(foo, 1); }
    </style>
    <p>TWO
    <p class=foo>THREE
    <p class=bar>FOUR
    <p part=my-p>FIVE
  </>
 </>
</>
```

* ONE is rendered in the outer "foo" font (standard behavior)
* TWO is rendered in the outer page's "foo" font (via inheritance, since the outer scope was captured at definition time)
* THREE is rendered in the shadow's "foo" font (specified via a style in the shadow tree, thus implicitly capturing the shadow as its scope)
* FOUR is rendered in the outer page's "foo" font (via explicit reference to the outer scope)
* FIVE is rendered in the outer page's "foo" font (specified via a style in the outer page, thus implicitly capturing the outer page as its scope)

-----

Scripting is a slightly thornier problem here. When setting styles, we can use the rules I've already laid out - you're always setting the style in some stylesheet (perhaps the implicit one attached to an element and accessed via `el.style`), so there's a consistent notion of an associated TreeScope.  (This may not always be *obvious*, but it's *clear* - a script that pokes around inside of the shadows of its components and sets styles needs to be aware of what scope the stylesheet is in and what scope the name-defining thing it's trying to reference is in.)

Reading styles is where we get tricky, particularly `getComputedStyle()` - what value should we serialize as? Typed OM has it easy, we can just literally give the value a `.scope` property or something that returns the TreeScope it's referring to.  (Probably define a `CSSScopedKeywordValue` subclass to cover that.)  Maybe we just shrug about the string-OM and you get whatever's in the stylesheet, even tho setting it back immediately onto `el.style` might not work?

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

Received on Friday, 17 November 2017 22:23:55 UTC