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

Provide an option which allows global CSSes to style elements inside a shadow tree #769

Closed
CarterLi opened this issue Oct 27, 2018 · 15 comments

Comments

@CarterLi
Copy link

CarterLi commented Oct 27, 2018

Motivation

Almost every website has global stylesheets. Lots of sites uses global resets such as * { box-sizing: border-box } ( for example Github ) or normalize.css. Some sites uses third party css libraries like bootstrap or fontawesome. All of them won't play well with ShadowDOM.

Components are not always designed for reuse. A component can be a page ( for SPA ), or a sort of elements in a page ( just because developers want to split their logics into a new file ). They still need style isolation to prevent styles escaping from their component scope but it doesn't mean they don't want global stylesheets.

The only option for now is including every global css files in ShadowDOM ( using <link> or @import ) for every component, which is complicate and may affect rendering performance because browsers need to parse CSS scripts for every component ).

Proposal

I'm suggesting a option that permits global styles to go in ( but forbids styles in ShadowDOM to go out ).

interface ShadowRootInit {
    mode: "open" | "closed";
    globalStyle?: 'permit' | 'forbid'; // proposed, default value is 'forbid' which is compatible with current behavior
}

The key name is not decided, for explanation only.

This proposal can be better than >>> and /deep/ because it is component itself that accepts outside styles instead of forcing a component applies them passively.

Sorry for my bad English. Any thoughts are welcome.

@CarterLi CarterLi changed the title Provide an option which allows global CSSes styling elements inside a shadow tree Provide an option which allows global CSSes to style elements inside a shadow tree Oct 27, 2018
@annevk
Copy link
Collaborator

annevk commented Oct 29, 2018

I don't think we want to allow * to match across trees, even if limited to CSS and not applicable to querySelector(). If a particular component isn't designed with reuse in mind, it's best to address that at the component level.

@emilio
Copy link

emilio commented Oct 29, 2018

Yeah, in particular the example you've proposed shows the problem doing this would have, which is that, if I write a component assuming that the regular layout box model is used, I definitely don't want it to be affected by your * { box-sizing: border-box } rule, for example.

@CarterLi
Copy link
Author

CarterLi commented Oct 29, 2018

Yeah, in particular the example you've proposed shows the problem doing this would have, which is that, if I write a component assuming that the regular layout box model is used, I definitely don't want it to be affected by your * { box-sizing: border-box } rule, for example.

In this case, just use globalStyle: 'forbid'

As I have explained, the default behavior is fit for component libraries, for example ng-material or element, to ensure that they are looked just like how they are designed everywhere.

But it's not the case in general development. In my project that I'm working on everyday, we are using * { margin: 0; padding: 0; }. I dont want to discuss whether it's a good design or not, but my teamates and I get used to it. If you force them to write the reset in every component, they will feel trouble.

Besides, we are using normalize.css, bootstrap, font-awesome; we have our own font icon library and css stylesheets. All of them are global.

@CarterLi
Copy link
Author

CarterLi commented Oct 29, 2018

I'd like to state that it's optional, and the default behavior wont break existing code. Many people have the same problem like me if you google it. I'd like to find a solution to make web component fit for more situations.

* /deep/ { kill: everything } is a bad idea but this isn't. We already have mode: "open" so why we can't let my component open for global stylesheets?

It's a bit like scoped styles. Scoped style is fit for my need but it's deprecated and never implemented in Chrome.

EDIT: What I mean global stylesheets is all <style>s and <link rel=stylesheet>s defined outside any shadow tree.

@hayatoito
Copy link
Contributor

hayatoito commented Oct 30, 2018

FYI. In case you missed the following proposals:

Edited: Link to the latest proposal

@CarterLi
Copy link
Author

FYI. In case you missed the following proposals:

Thanks for your information. I haven't seen them before.

  1. css-shadow-parts seems not to be what I want. It's still basically for components designed for reuse. For example I don't want to add part="whatever" on every element I use.
  2. construct-stylesheets seems to be what I need. Especially the section Applying Styles In All Contexts.

@caridy
Copy link

caridy commented Oct 30, 2018

@CarterLi the usage of a design system inside the shadow is definitely a crucial capability that we definitely need to have, whether that's bootstrap, material design or SLDS. We have been experimenting a lot with this, and we truly believe that constructable stylesheets could be a great solution, if we can get the perf right (which at this point I have no doubts that it is possible). Being able to share them between different components and the Document, and being able to opt-in into what design system do you want to include (what stylesheet do you want to adopt) seems to be good enough for many of us.

Consumers of those web components can simply control how those design systems are allocated so components importing those constructed stylesheets can be somehow controlled by the app running them seems algo good enough to apply certain app customizations across different components.

@CarterLi
Copy link
Author

@CarterLi the usage of a design system inside the shadow is definitely a crucial capability that we definitely need to have, whether that's bootstrap, material design or SLDS. We have been experimenting a lot with this, and we truly believe that constructable stylesheets could be a great solution, if we can get the perf right (which at this point I have no doubts that it is possible). Being able to share them between different components and the Document, and being able to opt-in into what design system do you want to include (what stylesheet do you want to adopt) seems to be good enough for many of us.

Consumers of those web components can simply control how those design systems are allocated so components importing those constructed stylesheets can be somehow controlled by the app running them seems algo good enough to apply certain app customizations across different components.

I agree. Is there any plan to put it on the agenda for discussion? @caridy

@rniwa
Copy link
Collaborator

rniwa commented Nov 6, 2018

So I think that's what ::theme is for. See https://drafts.csswg.org/css-shadow-parts/ and w3c/csswg-drafts#2368 There is an explainer at https://meowni.ca/posts/part-theme-explainer/

If we're adding some mechanism to associate a style with a custom element (see #468) then you could imagine that each component in your app could share a single programmatically shared stylesheet object as well.

@rniwa rniwa closed this as completed Nov 6, 2018
@rniwa rniwa reopened this Nov 6, 2018
@rniwa
Copy link
Collaborator

rniwa commented Nov 6, 2018

Oops, I didn't mean to close it.

@CarterLi
Copy link
Author

CarterLi commented Nov 6, 2018

So I think that's what ::theme is for. See drafts.csswg.org/css-shadow-parts and w3c/csswg-drafts#2368 There is an explainer at meowni.ca/posts/part-theme-explainer

No it isn't.

  1. I'm using * { box-sizing: border-box }. How can I make it apply to every element that I use? With ::theme I need to add part="my-element" to every element.
  2. I'm using normalize.css. How can I make it apply to every element that I use? I have to add ::theme(my-element) to every rule in the 3rd party file normalize.css.

What I need is not something about theming. It's about global resets or customized user agent stylesheets. It works without special configurations on elements that I write, but should not apply to 3rd party libraries / components unless their authors explicit say it should be.

@rniwa
Copy link
Collaborator

rniwa commented Nov 6, 2018

Okay, then I think #468 is what you want so that you can share that stylesheet object with multiple custom elements.

@caridy
Copy link

caridy commented Nov 6, 2018

@rniwa I think many folks will think that authoring a component and registering a component are analog, or carry on by the same group of people. That's only true if you own the application, and all the components running on it. But if you think about the distribution channels for components, npm will probably win, in which case, the registration of components is something that concerns to the app owner, while the developer can create components without having to make assumptions about what tag name will be used to register the component that they are creating. This is certainly the model that we use at Salesforce at a large scale.

Based on this model where there is no coordination (or very little) between the consumer of the component and the author, how can you expect that a component will be styled? aside from part/themes which are just expansion mechanisms for the component's API so you can style pieces of them, the two mechanism described above (adopted stylesheets and inert styles during registration) are things to consider, but I will argue that adopted stylesheets is more suitable for this use-case, because the author can opt-in to use a particular design system for the component, while the app's owner still have some control over the customization of that design system via the import resolution (whatever that will be).

@hayatoito
Copy link
Contributor

hayatoito commented Nov 12, 2018

Applying CSS rules from outside without opt-in from a component author (an owner of shadow tree) couldn't be a starter, in any case, I think. I am totally aware that there has been a strong demand for such a global stylesheeet primitive, however, any proposal would be hard to accept if the proposal doesn't require opt-in from a component author.

globalStyle?: 'permit' | 'forbid'; can be one of opt-in ideas, however, I would like to see how our existing lower primitive, such as Construtable Stylesheet objects, can be used by web developers to achieve the equivalent of global styleseet effectively in the user land, before rushing into such a higher primitive.

If there is still missing lower primitives, such as a hook for DocumentOrShadowRoot.adoptesStylesheet, we are happy to consider that.

Basically, we don't want to rush to provide higher primitives, without web developers having enough time to play with lower primitives and find more flexible way to achieve the goal. Higher primitives are unlikely to be flexible.

@annevk
Copy link
Collaborator

annevk commented Mar 16, 2019

Closing this per the last comment.

@annevk annevk closed this as completed Mar 16, 2019
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

6 participants