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

Make <link rel="stylesheet"> work inside shadow trees #4865

Closed
3 tasks done
baocang opened this issue Oct 5, 2017 · 8 comments
Closed
3 tasks done

Make <link rel="stylesheet"> work inside shadow trees #4865

baocang opened this issue Oct 5, 2017 · 8 comments
Assignees

Comments

@baocang
Copy link

baocang commented Oct 5, 2017

Description

is now supported in a shadow tree, see: whatwg/html@43c5786, but polymer can not load it with correct path. this maybe a bug of chrome, but can fixed in dom-module now.

Steps to Reproduce

  1. Create an application project: polymer init polymer-2-application named demo
  2. style demo with <link rel="stylesheet" href="./demo-app.css">
  3. Serve & open with polymer serve --open --open-path /

Expected Results

GET http://127.0.0.1:8003/src/demo-app/demo-app.css 200 OK

Actual Results

element-mixin.html:690 GET http://127.0.0.1:8003/demo-app.css 404 NOTFOUND

Browsers Affected

  • Chrome
  • Firefox
  • Safari

Versions

  • Polymer CLI: 1.5.5
  • node: v8.6.0
@baocang
Copy link
Author

baocang commented Oct 5, 2017

FYI:
just modify lib/elements/dom-module.html with few lines:

function resolveExternalStyleUrl(inst) {
	const template = inst.querySelector('template');
	const styles = template.content.querySelectorAll('link[rel="stylesheet"]');
	Array.prototype.forEach.call(styles, (style) => {
		style.setAttribute('href', Polymer.ResolveUrl.resolveUrl(style.getAttribute('href'), inst.assetpath));
	});
}

// Then, call correctExternalStyleUrl(this); in register(id)

@TimvdLippe
Copy link
Contributor

@sorvell sorvell self-assigned this Dec 12, 2017
@sorvell
Copy link
Contributor

sorvell commented Dec 14, 2017

While <link rel="stylesheet"> is supported in native implementations of ShadowDOM, there are problems with it and it is especially difficult to polyfill. We do eventually intend to provide some support for it in the ShadyCSS polyfill, but we do not consider this a high priority due to these issues.

Native Issues

Browsers typically block rendering on stylesheets that are in the document before it becomes interactive. This helps prevent FOUC. In order for a stylesheet in a shadowRoot to take advantage of this FOUC prevention, the shadowRoot must be created before the document becomes interactive. While this is possible, it's often not practical as element scripts are often loaded asynchronously. In this case, the element rendering will FOUC, which is typically not desirable. Further, even when the stylesheet is loaded, each rendered element that includes a <link rel="stylesheet"> will perform a fetch for this resource. Typically this will come from the browser cache, but it may not and in this case not only will the element produce FOUC, it will also need to download the stylesheet. Because of these issues, we recommend users avoid using <link rel="stylesheet"> inside shadowRoots.

Polyfill Issues

In order to polyfill scoped styling, ShadyCSS must have access to the text of the stylesheets being applied to the element. Unfortunately, there is no way to get the raw text of a <link rel="stylesheet"> natively. One would have to XHR for the resource separately and then would not be able to take advantage of render blocking or would need to use the dreaded sync XHR. Further, ShadyCSS currently rewrites style text once at definition time meaning that all styling is required when customElements.define is called. We intend to address this and when that is done, we can at least add some support for the feature, even though it will still produce FOUC.

@sorvell sorvell added p2 and removed p1 labels Dec 14, 2017
@bahrus
Copy link

bahrus commented Jan 3, 2018

Thanks, @baocang for raising this important issue, and the thoughtful response from @sorvell.

Using this approach to styling is a significant lowering of barrier to those of us who don't have time to build web components from scratch, but simply want to build on the great work of others by creating a low maintenance wrapper around third party framework agnostic api's. Especially during this time when @apply is being migrated to theme / parts. If whatever quirks there are with this approach can be worked out, I think it would result in a significant acceleration of web component adoption.

At the risk of stating the obvious, it is slightly different syntax from what Polymer mentions is deprecated, which may throw some developers off. At a minimum, I recommend that the Polymer documentation be updated to acknowledge, at least, that there is this syntax which isn't deprecated, and the potential pitfalls of using it, and what the workarounds might be.

To be honest, I'm not sure if it would be "correct" behavior for Polymer to perform url resolution of such stylesheet references automatically. Do the specs indicate the path is supposed to be evaluated relative to the [script] reference of the web component itself? If so, then I would second @baocang's proposal, in the sense that something is amiss (Chrome, maybe?). If the specs don't indicate this, it would still be useful, but maybe only if some custom polymer attribute is present, like "data-resolve"?

I've used this technique, hopefully I won't grow to regret it, so I've been awaiting critical analysis from the Polymer team. The polyfill seems to work fine in browsers like IE11, but I'm not aware of any issues like styles "leaking out" from the shadow DOM. Is that what the issue is with polyfills?

I can personally attest to the FOUC issue. But I find that it is fairly easy to rectify by not calling the third party rendering api until the load event finishes for the stylesheet, which seems par for what we can expect in today's brave new asynchronous world :

            const link = document.createElement('link');
            link.setAttribute('rel', 'stylesheet');
            link.setAttribute('type', "text/css");
            link.setAttribute('href', this._cssPath);
            link.addEventListener('load', e => {
                //do the render
            });
            this.shadowRoot.appendChild(link);

I also am not seeing any outright evidence of the stylesheet being loaded twice. If you go here: https://www.webcomponents.org/element/bahrus/billboard-charts/demo/demo/index.html in Chrome (make sure to refresh so you have the latest version), only one instance of billboard.min.css shows up in the network tab, even with caching disabled, even though there are two instances of the chart. Are you referring to something more subtle?

I do find that if I try to preload the style using the

<link rel="preload" as="style" href=".../billboard.min.css">

tag, then it does end up getting downloaded twice. This strikes me as one of several preload related bugs in Chrome (sigh). Any idea of it's been logged?

@bahrus
Copy link

bahrus commented Feb 8, 2018

For the record, I have now seen some cases where the css loads repeatedly. I used this technique with a web component that appears multiple times in a grid that uses virtual rendering (ag-grid). The initial display of row data, I only see one request for the css file. But when I start scrolling, I start to see multiple requests, even if I uncheck the "disable caching" checkbox (i.e. allow for some caching). This seems like something Chrome should fix (reminds me of IE6 behavior, to be honest).

@stale
Copy link

stale bot commented Mar 13, 2020

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 Mar 13, 2020
@stale
Copy link

stale bot commented Apr 16, 2022

This issue has been automatically closed after being marked stale. If you're still facing this problem with the above solution, please comment and we'll reopen!

@stale stale bot closed this as completed Apr 16, 2022
@yisibl
Copy link

yisibl commented Jul 8, 2024

Has FOUC improved with the release of declarative Shadow DOM?

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

5 participants