Skip to content

Javascript Interpolation in Styles via CSS Variables? #758

@colah

Description

@colah

Back in November, there was some discussion of whether svelte could support javascript variable interpolation in style sheets (sveltejs/v2.svelte.dev#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...

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions