-
Notifications
You must be signed in to change notification settings - Fork 683
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-scoping] Please bring back scoped styles #3547
Comments
I would love something like this. I've been experimenting with a custom HTML tag I call <style-container>
<div>Make me 500+ px wide</div>
<style media=none>
div {
border: 1px solid;
padding: 1em;
}
@media (min-width: 500px) {
div {
background: lime;
}
}
</style>
</style-container>
<script type=module>
import styleContainer from 'https://unpkg.com/style-container'
styleContainer()
</script>
From what I can see there are two main benefits:
|
@o-t-w I also, would like to see the re-visiting of scoped styles and would love to see this make a return. Being able to define a style that is scoped to a subset of elements would go a long way in terms of major use cases such as branding, consistency and the application of design systems in general. @tomhodgins You bring up a good point, what should this spec exactly cover? Simply the scoped keyword? As you mentioned there are lots of ideas that could bleed into this such as media queries, If memory serves me, it was the vendors that pushed back on the spec initially. Maybe we need to revisit their concerns and see what can be done to mitigate them as a start? I would be in favor of focusing on the scoped html attribute and possibly the reinstatement of the @Scoped keyword. Limiting the spec, I think, would help make it a lot more palatable for browser vendors. |
I think we need to separate the discussion of scoped styles as a concept from the specifics of the
I fully support this strategy. Can anyone outline specifically why decisions were made to not implement the But maybe there were other reasons from a browser performance perspective? I'd like to think that by rolling this back to the underlying needs and concerns, we can come up with a different syntax that addresses the needs without the same concerns. |
The reason why the Svelte, Vue, Angular but also styled-jsx (React) instead scope the styles to a single component to simulate ShadowDOM. eg: <style>
div { color: red }
div h1.foo { color: green }
</style>
<div>
<h1 class="foo">howdy</h1>
</div> in those frameworks becomes: <style>
div.scoped-123.scoped-123 { color: red }
div.scoped-123 h1.foo.scoped-123 { color: green }
</style>
<div class="scoped-123">
<h1 class="foo scoped-123">howdy</h1>
</div> This is done at build time. |
The already existing effort to implement it in Blink was actually removed because developers found it to be too complicated to develop Edge didn’t implement it for whatever reason, but this does not seem relevant anymore since Microsoft ditched its effort to develop an own browser engine altogether. Firefox on the other hand did implement |
Interestingly, per the current CSS Cascading Level 4 spec,
Doesn't this imply that, once CSS Nesting makes it into standard, it would be possible to write element-scoped styles as nested selectors inside the |
+1 to scoped styling making a return. Here's how I see it:
Shadow DOM really does not help, because it creates an arbitrary barrier (except for custom properties, but that's not actually enough; values only, not declarations and no mixin support). |
This does not simulate Shadow DOM. Shadow DOM prevents inheritance. The Vue behaviour (they actually emulate |
Shadow DOM doesn't prevent inheritance (it used to in v1). eg. |
To be clear: shadow DOM does not prevent inheritance, but it does prevent global selectors |
true
Not 100% sure about Vue (I think I checked once) and Angular but Svelte and styled-jsx act more like Shadow DOM. I am the co-author of styled-jsx and convinced Rich Harris (Svelte's creator) to switch from emulating |
update Vue also works like Svelte and styled-jsx https://codesandbox.io/s/ko4kp4nq5r https://vue-loader.vuejs.org/guide/scoped-css.html#mixing-local-and-global-styles Anyway this thread is not about frameworks I guess :) Eventually I don't mind if this makes it to the spec again but I don't think it is a proper solution the the lack of encapsulation in lite DOM. |
I don’t think this is accurate. When scope was in the spec, it was defined such that inner scopes overrode outer scopes, regardless of selector specificity. For example, given: /* in one scope */
.foo p {
color: blue;
}
/* in another scope */
.bar p {
color: red;
} A I also thought the final version of the spec, which relied on a |
@keithjgrant thanks for your reply that's useful information! I never looked at the Correct me if I am wrong: when using the inline (html attribute) version would styles cascade? If yes even in the case of Either ways the problem I am talking about is that with this model and no lower boundaries (like in JS components or Shadow DOM) it is impossible to stop styles from leaking into the entire subtree. The perfect example is you are making a website using some templating system. A partial has a |
Ah, yes. I see what you’re saying. I think you’re right. The question of styles “leaking in” is an interesting one. Because I think in most cases, there are some style you would want to leak in, and others you wouldn’t. Stepping back a bit, I think what I/we really want here is a first-class way to distinguish between base styles and “module” styles. Then you could define a bunch of base styles for the page (font family, color, default margins, etc.); these you would want to “leak in” to everything, as your default baseline. Then, on top of that, a way to define modular styles (module A has a blue heading, and some larger margins, module B has these borders, etc.); these you would want to scope only to their respective modules, and not leak in or out. Perhaps these modular styles can be done via Shadow DOM, but without a set of base styles that do pierce into all modules, they come up lacking. |
CSS Scoped Style spec proposal (@scope) which was removed due to lack of interest: https://www.w3.org/TR/2014/WD-css-scoping-1-20140403/#scope |
This is correct, I think (largely? Depends on the kind of properties?) But that makes it even worse, because it's so particular about what works and what doesn't. Yes: inheritance; no: global styles? When would you ever want to just inherit, but not have access to the global styles? Who thinks and works like that? |
@fantasai This looks good promising and interesting. To be clear, is this a new proposal you recently wrote? One concern is the limitation of using selector identifiers. Would this preclude from doing... <custom-element>
<div></div>
<style scoped>
div {
max-width: 60ch;
}
</style>
</custom-element> ... where Sorry if I have understood it poorly. |
@Heydon It's a proposal that was put together many years ago (the draft is dated 2014). It was dropped because nobody seemed to be interested in it. Work continued on Web Components, and the scoped style proposals were deleted from the specs. Wrt your example, doing exactly that would require bringing back HTML scoped styles, which is a different syntax for triggering the same behavior as @scope. In either case, you're binding some styles to a scoping root: the HTML syntax implies that relationship by placing the <style> element inside the scoping root, and the CSS syntax uses a selector. (The downside to the HTML approach is that you have to inject the style sheet into the markup. Which maybe isn't too bad if you only have one instance, but it can be pretty repetitive if you have multiple instances with the same styles!) If you wanted to tie some @scope'd CSS rules to a particular instance of custom-element, it's possible: you could do it with an ID selector, for example. @scope binds to whichever elements are selected by the @scope, and if you somehow manage to select only that custom-element instance (whether using ID selectors or some other method that happens to select only that one element) then it only binds to that instance. |
@Heydon good question! My take on this is that if you don't have global styles then probably inheritance should be opt-in too (as opposed to opt-out / status quo).
I have spoken with many supporters of styles in JavaScript and apparently they all do this (CSS Modules folks included). I guess they adopt a different strategy to avoid repetition: instead of using global and cascading styles they build up isolated components and reuse those instead. When it is time to tweak styles they then use custom properties or (in JavaScript) "context" by making explicit subscriptions so that they control what is affected by those changes. FWIW this proposal by Nicole Sullivan sounded interesting to me https://mobile.twitter.com/stubbornella/status/1076144685867982849 @keithjgrant The other day I was playing with another idea https://mobile.twitter.com/giuseppegurgone/status/1089633480458358785 but I am not sure how feasible it is without a way to mark DOM boundaries for the scope. This would be just an addition not a replacement of CSS. |
@fantasai, so does my assumption that the rules for the |
This is not the case. There are differences. To take a React example:
Here you could pass different props e.g. Whereas with just using a class, styles will override each other:
This API doesn't just account for scoping. It also accounts for two other things that have made CSS-in-JS popular:
|
The solution you are describing above already exists for React https://github.com/zeit/styled-jsx
This part is not super clear to me but without a lower boundary (or to simply put it per component encapsulation) the styles would style nested components (in React |
@SelenIT No, style attribute syntax doesn't allow selectors or at-rules. (The only reason style attributes are defined as "scoped" in that spec is to get the expected behavior--currently defined as "more specific than any selector". It's not introducing anything new.) |
@fantasai Thank you for the clarification! Some reflections:
My understanding is that this would be less repetitive than when writing CSS into a shadowRoot. Why? Because you can still draw upon already set global styles. Currently, when I write a custom element, the only easy way to use styles specific to an instance of that element is through Shadow DOM. And once I start using Shadow DOM, I have to play with its rules — including not being able to use global style rules. |
We could use |
Is there a reason to prefer the HTML attribute approach over a |
@SebastianZ This is what the original 2014 proposal did, except instead of using a special name to tie the @scope and the element together, you could use any selector. |
Fwiw there was some discussion on this topic on the CSSWG call this week, see minutes at |
Good news, This will be implemented here: https://chromium-review.googlesource.com/c/chromium/src/+/4161741 In order to push all browsers to implement it, you can go to the interop 2023 issue to show your support. |
This project is living in the future: https://github.com/gnat/css-scope-inline Keep the syntax simple and short, friends. I want to see |
The scoped style tag HTML attribute works really well with popular frameworks and is far simpler to use than shadow DOM.
e.g. in React:
Shadow DOM offer more encapsulation than scoped styles, but this level of encapsulation is not often needed, and even sometimes complained about by developers.
e.g. Chris Coyier:
It is important to note that both Vue js and Svelte have replicated this API - it is clearly an API that is both easy to work with and gives the right level of encapsulation (unlike shadow DOM, which is useful for more niche cases).
At the moment people are using many different solutions (CSS Modules, Styled Components and all the other CSS-in-JS options). It would be great if there was a standardized way to solve the problem of scoping rather than the very fragmented options in user-land. I strongly doubt that shadow DOM will prove to be a popular solution capable of attracting people away from these libraries.
A prior discussion about the topic can be found here: #137
The text was updated successfully, but these errors were encountered: