Useful or not, from you.
svelte Javascript Interpolation in Styles via CSS Variables?

Back in November, there was some discussion of whether svelte could support javascript variable interpolation in style sheets (sveltejs/svelte.technology#9). Unfortunately, this didn't seem feasible, since CSS classes are per class, and can't be specialized per instance.

It seems like this could be possible using CSS variables. Consider adding the following (functional) svelte code to the standard counter example:

<div class="bar" style="--count:{{count}}"></div>

<style>
  .bar {
    width: calc(40px * var(--count) );
  }
</style>

This sort of pattern might be attractive for a a few reasons:

  • It avoids messy inline styling.
  • It allows pure CSS for certain kinds of interactivity (eg. :hover).
  • It may (?) be faster in certain situations like spritemap manipulation where one wants to prevent certain parts of the style from being updated? (I don't understand the underlying model well enough to know if or when this would be true).

(To be clear, I've only done a few toy things this way. I'm completely open to the possibility that it may not be a good idea at all!)

While the example above works, and might be handy, it seems unnecessarily clunky. It also runs a risk that CSS variables may end up with different names than their JS counterparts, accumulating technical debt.

Potential Svelte Integration

If svelte wanted to facilitate this kind of pattern, there's a broad spectrum of options it could take.

  1. At the very mild end, it could support a kind of CSS variable binding syntax. This could cut down on repretition and encourage variable names to stay in sync:
<div class="bar" css_bind:count ></div>
  1. The next step up might be to detect variable usage and implicitly bind them. So you'd just do this without explicitly setting up --count:
width: calc(40px * var(--count) );
  1. Yet stronger might be to allow javascript variables through the usual syntax and implicitly create the css variable:
width: calc(40px * {{count}} );

Or maybe this, if you wanted to still remind the user that it's a variable:

width: calc(40px * var({{count}}) );
  1. Finally, one could go all the way in:
width:  {{40 * count}}px;

Which would compile into something like:

<div class="bar" style="--svelte-css-1234:{{40 * count}}px"></div>

<style>
  .bar {
    width: var(--svelte-css-1234);
  }
</style>

Potential Downsides

  • This could lead to less transparent CSS code when inspected in the browser. Compare:
width: 120px;

--count: 3;
width: calc(40px * var(--count) );

--svelte-css-1234: 120px;
width: var(--svelte-css-1234);

On the flip side, it may make some things more transparent -- especially if we can keep variable names synced to javascript.

  • It may also complicate the model for understanding what your code is doing behind the scenes...
That's a useful answer
Without any help

Here's a REPL with the Counter example in v3.

It's not too cumbersome, but some support for doing it directly in CSS, while keeping compatibility with other preprocessors would be great.

Something like this:

<input type=number bind:value={count}>
<button on:click={() => count += 1}>count</button>
<div class="count-bar"></div>

<!--
var-prefix could be optional, default would just be '--' which 
would replace all CSS vars that match a component variable.
However, specifying it improves readability as it makes 
intent explicit.
And perhaps it should be required to enable replacement, so
as to avoid surprises with unexpected replaced vars.
-->
<style var-prefix='--s-'> 
	.count-bar {
		height: 40px;
		width: calc( var(--s-count) * 1px + 1px);
		background-color: gray;
	}
</style>