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

[ShadyCSS] Constructible Stylesheets and adoptedStyleSheets support for browsers with native shadow DOM #44

Open
justinfagnani opened this issue Apr 17, 2019 · 4 comments

Comments

@justinfagnani
Copy link
Collaborator

Constructible Stylesheets

We want to support and API as close as possible to native Constructible Stylesheets, so that this works:

const s = new CSSStyleSheet();
s.replaceSync(':host { display: block } ');

This may be achievable by overwriting the CSSStyleSheet constructor with one that creates a stylesheet in a shadow root. Something like:

const container = document.createElement('constructible-stylesheets');
container.attachShadow({mode: 'open'});
document.append(container);

const originalCSSStyleSheet = CSSStyleSheet;
CSSStyleSheet = class extends originalCSSStyleSheet {
  constructor() {
    this._styleElement = document.createElement('style');
    container.shadowRoot.append(this._styleElement);
    Object.setPrototypeOf(this, this._styleElement.sheet);
  }

  replaceSync(styleText) {
    this._styleElement.data = styleText;
  }
}

(I haven't tried this code)

adoptedStyleSheets

ShadowRoot.adoptedStyleSheets could be implemented with a setter that only accepts arrays of stylesheets created as above with a _styleElement property. It would then clone those style elements and insert them last into the shadow root.

To protect against mutations of the shadow root that remove the styles, we can put them in a custom element called <adopted-stylesheets> that adds itself back to the shadow root if it's ever removed.

const allAdoptedStylesheets = new Set();
class AdoptedStylesheetsElement extends HTMLElement {
  constructor() {
    super();
    allAdoptedStylesheets.add(this);
  }

  connectedCallback() {
    this._previousRoot = this.getRootNode();
  }

  disconnectedCallback() {
    this._previousRoot.append(this);
  }
}

allAdoptedStylesheets can be used to update cloned style tags incase replace or replaceSync is called on a CSSStyleSheet.

cc @azakus

@dfreedm dfreedm transferred this issue from webcomponents/webcomponentsjs Jun 7, 2019
@dfreedm dfreedm self-assigned this Jun 12, 2019
@dfreedm dfreedm changed the title Constructible Stylesheets and adoptedStyleSheets support for browsers with native shadow DOM [ShadyCSS] Constructible Stylesheets and adoptedStyleSheets support for browsers with native shadow DOM Jun 12, 2019
@dfreedm dfreedm added Severity: High Type: Feature New feature or request labels Jun 13, 2019
@arimeq
Copy link

arimeq commented Jun 17, 2019

While implementing this enhancement, please mind the CSP (Content-Security-Policy). Some applications may have a very strict policy (e.g. forbid inline anonymous <style> elements), which may cause a lot of problems. One of possible ways of working around this issue would be to provide a possibility of using a nonce attribute on <style> element:

CSSStyleSheet = class extends originalCSSStyleSheet {
  (...)
  fixCsp(nonce) {
    this._styleElement.nonce = nonce;
  }
}

This would result in attaching <style nonce="..."> element to (shimmed?) shadow DOM, and this could satisfy CSP's needs. (Of course that nonce value must be provided by code that uses ShadyCSS.)

@Lodin
Copy link

Lodin commented Sep 6, 2019

@justinfagnani, the construct-styles-sheets-polyfill project may be interesting for you. It supports the adoptedStyleSheets functionality in the following ways:

  • For all the browsers with native support for web components, it supports document-level and shadow root-level style sheets adoption.
  • For browsers without support for web components (IE 11 and stable Edge for now), it implements only the document-level style sheet adoption.

It can also be used along with the ShadyCSS's prepareAdoptedCssText because their functionalities do not overlap.

@enricomarino
Copy link

const originalCSSStyleSheet = CSSStyleSheet;
CSSStyleSheet = class extends originalCSSStyleSheet {
  constructor() {
    //...
  }
}

CSSStyleSheet is not instantiable, so it's not extensible either ...

@stale
Copy link

stale bot commented Dec 14, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Dec 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants