Description
Is your feature request related to a problem? Please describe.
I want to have a common part of the CSS style, at the same time also I don't want to have to throw every little bit of CSS out of the *.svelte
files and I don't want to use global CSS.
Describe the solution you'd like
CSS Binding and Passing.
It is the most intuitive, transparent and sveltish solution, at the same time referring to the CSS assert in custom element proposal.
Style set in App.svelte
in style
tag with bind:styles
attribute, passed to the Component.svelte
and Component2.svelte
components in style
with styles
atribute. Scoped.
Example:
<!-- App.svelte -->
<script>
import Component from "$lib/components/Component.svelte";
import Component2 from "$lib/components/Component2.svelte";
let styles;
</script>
<Component styles={styles}>
<Component2 styles={styles}>
<style bind:styles={styles}>
/* simple styles */
</style>
<!-- Component.svelte -->
<script>
export let styles;
</script>
<style styles={styles}/>
-
Style should not be global, but scoped at the point of use.
-
I can see that in every component with
<style styles={styles} />
, the same hash likesvelte-n323vl
is used for classes. -
The variable
styles
is an object that cannot be modified, it is used only to pass the preset style to the component.
Questions:
-
It should be possible to use multiple
style bind:styles={styles}
(both declaration and use) and plain<style>
at the same time.
Is something in the way?
OR:<style bind:styles={ [styles, styles2] } />
or<style bind:styles={ {...styles, ...styles2} } />
- and only the declaration could be multiple. -
Should the binded
style
inApp.svelte
also be applied to the HTML elements inApp.svelte
?
Or should it be optional? Attribute of typeonlydeclaration
(I don't have a good idea of the name).
<style bind:styles={styles} onlydeclaration>
/* simple styles */
</style>
I don't know if it should work in App.svelte
by default and need to be turned off with the attribute, or vice versa?
Another option - better? - at the same time simpler, but also a bit circular (OF COURSE, this is not usually used, only in exceptional cases):
<!-- App.svelte -->
<style bind:styles={styles}>
/* simple styles */
</style>
<style styles={styles}/>
or even just:
<!-- App.svelte -->
<style bind:styles={styles} styles={styles}>
/* simple styles */
</style>
- Should css custom properties work?:
<!-- App.svelte -->
<script>
import Component from "$lib/components/Component.svelte";
import Component2 from "$lib/components/Component2.svelte";
let styles;
</script>
<Component styles={styles}>
<Component2 styles={styles}>
<style bind:styles={styles}>
div {
background-color: var(--css-var);
}
</style>
<!-- Component.svelte -->
<script>
export let styles;
</script>
<div style="--css-var: red;"></div>
<style styles={styles}/>
Probably yes, but maybe there will be some obstacles?
-
Maybe in order for
<style bind:styles={styles}></style>
to not confuse with the standard<style></style>
behavior (i.e. applying styles toApp.svelte
), you need to use<svelte:style bind:styles={styles}></svelte:style>
? -
Other idea...:
Instead of requiring separate tags (<style bind:styles>
or<svelte:style bind:styles>
), I figured out a way to keep the number of<style>
tags constant.
<!-- App.svelte -->
<script>
import Component from "$lib/components/Component.svelte";
import Component2 from "$lib/components/Component2.svelte";
let styles;
</script>
<Component styles={styles}>
<Component2 styles={styles}>
<style bind:exposed={styles}>
:expose {
/* exposed styles */
}
/* App.svelte own styles */
</style>
<!-- Component.svelte -->
<script>
export let styles;
</script>
<style styles={styles}>
/* Component.svelte own styles */
</style>
Where:
- everything contained in
:expose {}
has a separate hash - binds to the styles object is the hash of the elements in
:expose {}
- using the styles object in
<style styles={style}>
causes the hash to be used inComponent.svelte
elements - Component.svelte has its own hash, and the one passed is an additional hash, e.g .:<p class="svelte-15kka16 svelte-edszo3"></p>
svelte-15kka16
is the hash added withstyles={styles}
andsvelte-edszo3
is the hashComponent.svelte
. - styles in
:expose {}
default are NOT applied toApp.svelte
. To make them, you have to use:<style bind:exposed={styles} styles={styles}>
I think it would be nice to be able to name the displayed block styles and use more than one:
<!-- App.svelte -->
<script>
import Component from "$lib/components/Component.svelte";
import Component2 from "$lib/components/Component2.svelte";
let styles;
</script>
<Component styles={styles.name1}>
<Component2 styles={styles.name1}>
<style bind:exposed={styles}>
:expose(name1) {}
:expose(name2) {}
Each of them would have a separate hash.
Most importantly, it is not global, and is controlled where this :expose {}
block is to be used.
Summary:
The whole thing seems clear, refers to the upcoming standard, and at the same time is "sveltish".
Describe alternatives you've considered
<style>
:global(...)
</style>
<svelte:head>
<link rel="stylesheet" href="styles.css">
</svelte:head>
<style src="./styles.css"></style>
<style>
@import "./style.css";
</style>
- Svelte component custom properties
<Component --css-var={var}>
Passing CSS custom properties to components rfcs#13 - closed https://github.com/AlbertMarashi/rfcs/blob/patch-1/0000-allow-parent-to-impact-child-css.md
- Some kind of libs?
svelte-css-in-js
modular-css
Some do not work, none offer the type of possibilities I suggest, nor are they so sveltish.
If anyone wants to do RFC, please do.
How important is this feature to you?
The point is not to use global CSS or do some redundant CSS.
In fact, such something is needed all the time.
This is where my basic proposition ends.
FURTHER THINKING - Import CSS file and Passing Classes:
Import CSS file
Seems like can be used to... import CSS.
There is a proposition import styleSheet from "./styles.css" assert { type: "css" };
for WebComponents.
<!-- Component.svelte -->
<script>
import Component from "$lib/components/Component.svelte";
import Component2 from "$lib/components/Component2.svelte";
import styles from" ./styles.css "assert {type: "css"};
</script>
<Component styles={styles}>
<Component2 styles={styles}>
<style styles={styles}/>
Such an imported svelte style would also be scoped.
I can see an easy use of this in <svelte:options tag="my-element" />
.
I will not be surprised if such placing of imported CSS will be interesting for someone, and passing between components less...
Question:
Do you allow import ("./styles.css", {assert: {type: "css"}});
? Probably not.
Passing Classes
Binding classes with the style
tag and passing to components. Extracting classes from the binding variable style
.
Example:
<!-- App.svelte -->
<script>
import Component from "$lib/components/Component.svelte";
import Component2 from "$lib/components/Component2.svelte";
let styles;
</script>
<Component el={styles.el}>
<Component2 styles={styles}>
<style bind:styles={styles}>
.el {
/* props */
}
</style>
<!-- Component.svelte -->
<script>
export let el;
</script>
<div class="el"></div>
<style styles={{el}}/>
...or as in css-modules
?:
<!-- Component.svelte -->
<script>
export let el;
</script>
<div class={el}></div>