MicrosoftEdge / MicrosoftEdge/MSEdgeExplainers

[Declarative Shadow DOM Style Sharing] Use fragment URLs instead of global specifiers

Open
#1,186 5 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

DeclarativeShadowDOMStyleSharing
Dominant language
HTML
Stars
1.4k
Forks
286
Avg merge
3d 1h
Merged PRs (30d)
8

Description

I'm worried about the choice of using a global namespace for inline stylesheets. We have been generally regretting the usage of global namespaces, as they make adoption significantly harder because they require global coordination across the whole application. I'm especially worried in the context of https://github.com/WICG/webcomponents/blob/gh-pages/proposals/html-modules-explainer.md, which allows developers to publish self-contained HTML files (different from the "root" one) that contain a template with the corresponding style.

I understand that there are benefits to using global specifiers, since it means you can reach them from anywhere. However, I'd like to suggest an alternative that should retain the same benefit while avoiding the global namespace problem: using URL fragments. They have been designed exactly to refer to a part of a larger document.

For context, this idea also came up in the context of https://github.com/tc39/proposal-module-declarations, which also introduces a single file that internally defines multiple (JavaScript in that case, instead of CSS) modules.

Specifically, https://example.com/index.html#foo would be the fully resolved URL for the <style type="module" specifier="foo"> defined inside https://example.com/index.html#foo. We can make URL resolution work like it does for new URL("#foo", <this file's URL>), so that you can reference that inline stylesheet:

  • using #foo from inside https://example.com/index.html:
    <style type="module" specifier="foo">
      #content {
        color: red;
      }
    </style>
    <my-element>
      <template shadowrootmode="open" shadowrootadoptedstylesheets="#foo">
        ...
      </template>
    </my-element>
    
  • using, for example, ../index.html#foo from a hypotetical https://example.com/js/bundle.js#foo:
    import styles from "../index.html#foo" with { type: "css" }
    
  • using absolute URLs whenever you want, like you can do for "external" files

If users do want to have a global alias, they can use an import map for it. But it's opt-in, like for any other module. They could also use imoprt map scopes, to have an absolute-like specifier that is not actually absolute.

<script type="importmap">
{
  "imports": {
    "foo": "#foo"
  }
}
</script>

There is one drawback to this approach: it's that import "./something#foo" is already valid, and it currently resolves to the same module as ./something. There are two possible solutions to this:

  1. When doing import "./something#foo":
    • if ./something exposes a #foo sub-module we return it
    • otherwise we return ./something's whole thing
  2. When doing import "./something#foo":
    • if ./something exposes a #foo sub-module we return it
    • otherwise, if ./something exposes any sub-module, we error
    • otherwise we return ./something's whole thing

EDIT: This approach also suggests a consistent way to directly import "sub-modules exported from a module", which assuming https://github.com/WICG/webcomponents/blob/gh-pages/proposals/html-modules-explainer.md + https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/AtSheet/explainer.md + https://github.com/tc39/proposal-module-declarations can happen with:

  • an HTML module exporting a bunch of CSS modules
  • a CSS module exporting a bunch of CSS modules
  • a JS module exporting a bunch of JS modules

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading this proposal alongside the linked HTML Modules, module declarations, and AtSheet explainers, then compare the suggested fragment-URL resolution with the existing global-specifier approach. A complete contribution would clarify the resolution rules and whether the proposal should replace or extend the current design.

Written by the indexing model from the issue text.

Assessment

Tech stack
css, html, javascript
Domain
frontend, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.