Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-cascade] Shadow DOM style ordering and cascade penetration #11547

Open
dead-claudia opened this issue Jan 20, 2025 · 1 comment
Open

[css-cascade] Shadow DOM style ordering and cascade penetration #11547

dead-claudia opened this issue Jan 20, 2025 · 1 comment

Comments

@dead-claudia
Copy link

dead-claudia commented Jan 20, 2025

First filed in whatwg/dom#1348, but that was the wrong repo

What problem are you trying to solve?

I want to be able to use shadow DOM for display encapsulation, but while still being able to use global styles and participate in its inheritance.

What solutions exist today?

Currently, I could use shadowRoot.adoptedStyleSheets = [...globalSheets]. But doing this comes with a cost: these style sheets take precedence over local <style> elements (this can be easily worked around by removing the element and adopting its parsed style). Furthermore, it doesn't work with declarative shadow DOM at all.

Alternatively, I could inject all the global styles with duplicate <link rel="stylesheet">s. This comes with serious performance concerns: imagine a hundred posts on a TweetDeck-style UI for a microblogging site, each with <format-time> to format the time, <user-link> to format the username, and <format-text> to format the text. If you have 5 stylesheet tags on the site (say, normalize.css, your site's styles, Bootstrap, and a couple Bootstrap plugins) and want to use them all in that custom element's shadow DOM, that's 500 <link rel="stylesheet"> elements in that one page. The browser can cache style parsing per-URL to avoid the memory blow-up, but the browser can't avoid having to compute the entire stylesheet for every page, leading to high style compute times.

And in both cases, the cascade can't go through the shadow DOM.

How would you solve it?

Add a styleOrder ordered token list option for shadow root initializers:

  • outer - Set to apply parent styles.
    • If a shadow host is in a div in a parent and the corresponding shadow root's children has a span, the CSS selector div span would match the inner child.
    • If a shadow host is a foo-bar in a parent and the corresponding shadow root's children has a top-level span, the CSS selector foo-bar > span would match the inner child.
  • adopted - Set to apply adopted stylesheets. If not included, shadowRoot.adoptedStyleSheets has no effect.
  • inner - Set to apply inner stylesheets. If not included, inner <style> and <link rel="stylesheet"> elements have no effect.

The default, to match today's behavior, is styleOrder: "inner adopted". My problem would be addressed via styleOrder: "outer adopted inner".

Yes, this is intentionally immutable. It needs to be for perf reasons.

Yes, this allows disabling CSS customization entirely. But that's not the point, and I'm intentionally not proposing a way to disable scripting here.

For declarative shadow DOM, styleOrder can be specified via shadowrootstyleorder="...".

Anything else?

This addresses one of the big impediments to prerendering web components in my experience.

@dead-claudia
Copy link
Author

Yes, this obviously has interactions with HTML and the DOM. The DOM part could be addressed here, while HTML's parser spec would at minimum need modified to point here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant