[WICG/webcomponents] Declarative CSS Module Scripts (#939)

Declarative shadow roots and constructible stylesheets need to be made to work together so that stylesheets added to shadow roots can be round-tripped through HTML serialization and deserialization.

As of now, SSR code will have to read a shadow root's adopted stylesheets and write them to HTML as `<style>` tags. While this will style they shadow roots correctly on first render, it results in bloated a HTML payload and breaks the shared stylehseet semantics. Hydration code would have to deduplicate `<style>` tags and create and attach constructed stylesheets in order to reconstruct the origin DOM structure.

To solve this we need a serialized for of constructible stylesheets. These are stylesheets that do not automatically apply to any scope, but can be associated and applied by reference.

Requirements:
1. Ability to serialize a constructed stylesheet to HTML
2. Styles don't automatically apply to the document or any shadow root
3. Styles are able to be associated with declarative shadow root instances
4. To support streaming SSR, the styles must be able to be written with the first scope that uses it and referenced in later scopes.

One idea is to add a new type for `<style>` tags that accepts CSS text and creates a new constructed stylesheet:

```html
  <style type="adopted-css" id="style-one">
    :host {
      color: red
    }
  </style>
```

This style can then be associated with a declarative shadow root:

```html
  <my-element>
    <template shadowroot="open" adopted-styles="style-one">
      <!-- ... -->
    </template>
  </my-element>
```

Having a type other than text/css means that the styles won't apply to the document scope even in older browsers. It's also what allows it to have an adoptable CSSStyleSheet .sheet, which replace() works on as well.

One problem that immediately come up is scopes and idrefs. If a declarative stylesheet is only addressable from within a single scope, it's no better than a plain `<style>` tag because it would have to be duplicated in every scope that uses it. We need some sort of cross-scope idref mechanism. With that we can write the styles with the first scope that uses them, and reference them in later scopes in the document:

```html
  <my-element>
    <template shadowroot="open" adopted-styles="x61h8cys">
      <style type="adopted-css" xid="x61h8cys">
        :host {
          color: red
         }
      </style>
      <!-- ... -->
    </template>
  </my-element>
  <my-element>
    <template shadowroot="open" adopted-styles="x61h8cys">
      <!-- ... -->
    </template>
  </my-element>
```

Here `xid` is a stand-in for some kind of cross-scope ID. `"x61h8cys"` is a stand-in for a GUID or other globally unique value (such as a hash of the style text) that the SSR code would be responsible for generating.

There are other instances where we need cross-scope references, like ARIA and label/input associations. I'm not sure if these cases are similar enough to use the same mechanism or not.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/WICG/webcomponents/issues/939

Received on Monday, 16 August 2021 16:39:09 UTC