-
Notifications
You must be signed in to change notification settings - Fork 82
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-in-HTML #6
CSS-in-HTML #6
Conversation
Css vars via @lukeed: <div class="demo">
<button on:click={() => value++}>Increment</button>
<button on:click={() => value--}>Decrement</button>
</div>
<script>
export let value = 0;
</script>
<style>
.demo {
padding: 10px;
border-radius: 4px;
-webkit-appearance: none;
font-style: italic;
/* this is dynamic */
color: {value % 2 ? green : red};
}
</style>
<!--
Output (legacy:true)
needs :yak: symbol because
it writes inline style properties
but will overwrite anything meant to cascade
-->
<style>
.demo {
padding: 10px;
border-radius: 4px;
-webkit-appearance: none;
font-style: italic;
}
</style>
<div class="demo" style="color:green;">...</div>
<div class="demo" style="color:red;">...</div>
<!--
Output (legacy:false)
sets (--var) values inline, which
will respect cascade bcuz does not
change the style-rules or their order
-->
<style>
.demo {
padding: 10px;
border-radius: 4px;
-webkit-appearance: none;
font-style: italic;
color: var(--color);
</style>
<div class="demo" style="--color:green;">...</div>
<div class="demo" style="--color:red;">...</div> |
A couple others for quick reference: |
GlobalThis has been discussed elsewhere, but I think building off of #4 with the multiple script tag approach (with
<style context="global">
body { background: #111; }
h1 { font-size: 3rem; }
/* Equivalent to:
:global(body) { background: #111; }
:global(h1) { font-size: 3rem }
*/
</style>
<style>
a { color: white; }
</style> CascadeFor cascading styles (apply from component to children),
<style>
section :global(.Post__title) { color: blue; }
section Post::part(body) { line-height: 1.5; }
/* Equivalent to
section.svelte-id .Post__title { color: blue; }
section.svelte-id [part="body"].svelte-Postid { line-height: 1.5; }
*/
</style>
<section>
<Post primary title="..." body="..." />
</section> <!-- Post.html -->
<h1 class="Post__title">>{title}</h1>
<!-- ^ 2. Classes -->
<div part="body" style="color: {primary ? 'blue' : 'grey'}">{body}</div>
<!-- ^ 3. Parts ^ 1. Properties --> Edit: additionally, it looks like <style context="global">
:root::theme(body) { background: orange; }
/* Equivalent to
:root [part="body"] { background: orange; }
*/
</style>
<style>
section::theme(body) { background: yellow; }
/* Equivalent to
section.svelte-id [part="body"] { background: yellow; }
*/
</style> (I think that's how Edit: added some notes on the cascade options |
RE @timhall's last point:
|
@timhall regarding scoping via separate Method with scoped tags: <style context="global">
.component {
font: inherit;
h1 { margin: 0 0 0.2rem; }
h2 { margin: 0; }
p { color: goldenrod; }
}
/* precompiles to:
.component { font: inherit; }
.component h1 { margin: 0 0 0.2rem; }
.component h2 { margin: 0; }
.component p { color: goldenrod; }
*/
</style>
<style>
/* overriding locally */
.component {
color: pink;
font: 1.6rem/1.2 Helvetica;
h1 { margin: 0; }
h2 { margin: 0 0 2rem; }
p { color: inherit; }
}
/* precompiles to:
.component {
color: pink;
font: 1.6rem/1.2 Helvetica;
}
.component h1 { margin: 0; }
.component h2 { margin: 0 0 2rem; }
.component p { color: inherit; }
*/
</style> Alternate proposal with scoped <style>
.component {
color: pink;
font: 1.6rem/1.2 Helvetica;
h1 { margin: 0; }
h2 { margin: 0 0 2rem; }
p { color: inherit; }
@global {
font: inherit;
h1 { margin: 0 0 0.2rem; }
h2 { margin: 0; }
p { color: goldenrod; }
}
}
/* precompiles to:
.component {
color: pink;
font: 1.6rem/1.2 Helvetica;
}
.component h1 { margin: 0; }
.component h2 { margin: 0 0 2rem; }
.component p { color: inherit; }
@global {
.component { font: inherit; }
.component h1 { margin: 0 0 0.2rem; }
.component h2 { margin: 0; }
.component p { color: goldenrod; }
}
*/
</style> It's a pedantic difference, but I find the latter grouping / clustering much more easy to deal w/, arrange, and (in part) keep DRY. |
@lukeed > The idea here is that we follow the :global and :local convention I am in favor of (if not abandoning) those microscopic selectors (they cause a lot of clutter), at least replacing with something that encapsulates better, i.e., a (🐃) |
Was just following the rest of V3's approach of reusing existing syntax. I'm not familiar enough with latest improvements to CSS modules/PostCSS, but to me it's more appealing to construct CSS in a way that these tools can understand, in the event I'm porting styles to & from Svelte SFCs to standalone stylesheets. |
@arxpoetica I think your example is a good case for preprocess plus postcss-nested and postcss-global-nested and why building on the "standard"ish .component {
color: pink;
font: 1.6rem/1.2 Helvetica;
h1 { margin: 0; }
h2 { margin: 0 0 2rem; }
p { color: inherit; }
:global {
font: inherit;
h1 { margin: 0 0 0.2rem; }
h2 { margin: 0; }
p { color: goldenrod; }
}
}
/* Transformed in preprocess using postcss-nested and postcss-global-nested to */
.component {
color: pink;
font: 1.6rem/1.2 Helvetica;
}
.component h1 { margin: 0; }
.component h2 { margin: 0 0 2rem; }
.component p { color: inherit; }
.component :global (
font: inherit;
}
.component :global(h1) { margin: 0 0 0.2rem; }
.component :global(h2) { margin: 0; }
.component :global(p) { color: goldenrod; } Alternatively, I've run into many issues with using global css frameworks like bootstrap or tailwindcss and getting about a thousand unused style warnings so it'd be nice to have an escape hatch for processing style blocks from a global context. For overloading <!-- Button.html -->
<button part="button"><slot name="button" /></button> <Button>Howdy!</Button>
<style>
Button::part(button) {
/* Applies to the button element itself */
}
:Button('button') {
/* Applies to what is contained in the slot */
}
</style> Edit: Fix preprocess (postcss) transform |
My main hesitation with the proposed In this last example, it looks okay because Similarly, in the first example you provided ( I think we should be allowed to target DOM elements within the Component. But if we're to add styles to parts/slots, that those have to be passed thru as name strings for clarity & distinction. |
That's a very good point and I think a confusing part of the proposal, with Edit: Looks like it's not unprecedented to use the bare string in pseudo-classes with |
Aside FWIW, before continuing, I should clarify my idea about using For it to be useful, Svelte slots would have to operate like Vue's in that they can exist on their own (Svelte's current & only approach) or be applied onto an another element (much like @timhall's <slot />
<slot name="foo" />
<div class="hello" slot="bar" />
However, even if @Rich-Harris allowed this to happen (I don't think he's a fan? hence current implementation), I don't know if they realistically would be very enjoyable to use because you (as the Parent component) would need to know if the I mean, either thru 🤔 I'd be happy with this & think it solves a lot of the conversation re: Component style inheritance & overwrites: <!-- Actions.html -->
<div class="actions">
<div slot="primary" />
<div slot="secondary" />
<button>Cancel</button>
</div> <!-- Parent.html -->
<Actions>
<button slot="primary">Submit</button>
<button slot="secondary">Edit</button>
</Actions>
<style>
:Actions(button) {
/* apply to all <button> within Actions */
/* ==> button x3 (Submit, Edit, Cancel) */
}
:Actions('primary') {
/* applies to the "div[slot=primary]" element directly */
/* ==> <div> x1 */
}
:Actions('primary') button {
/* applies to the "div[slot=primary] button" element directly */
/* ==> <button> x1 (Submit) */
}
:Actions('secondary') button {
/* applies to the "div[slot=secondary] button" element directly */
/* ==> <button> x1 (Edit) */
}
</style> |
@timhall (and @lukeed) there's a lot to unpack here, so let's just take it one step at a time. How exactly is this a correct precompile translation: .component {
:global {
font: inherit;
h1 { margin: 0 0 0.2rem; }
h2 { margin: 0; }
}
}
/* Transformed in preprocess using postcss-nested and postcss-global-nested to */
:global(.component) {
font: inherit;
}
.component :global(h1) { margin: 0 0 0.2rem; }
.component :global(h2) { margin: 0; } Wouldn't it compile to: .component :global { font: inherit; }
.component :global h1 { margin: 0 0 0.2rem; }
.component :global h2 { margin: 0; } Or is their something special in |
@arxpoetica Oops, fixed the |
c81076e
to
0dc6590
Compare
JS variables inside style blocks is a TERRIBLE idea. The nightmare scenarios this would create in terms of debugging would just be astronomical. Better to keep the 2 separate. If you find a use case for something like this, then aphroditeJs or other CSS js frameworks would be more ideal. |
Closing this in favour of #13 |
Rendered
Even though this is an incomplete proposal, there's been so much conversation in the #future Discord channel, I wanted to give us a place to record some of the conversation more inline with the (ongoing) proposal.
Expect some of those conversations to start to land.
If we find this PR to become too encumbered with old ideas, I'll close it and reopen a new one after incorporating some of the top / sanctioned ideas.
But for now, consider this just a good place to capture ongoing discussion.