Change CSS at runtime in Single File Components

I’m trying to dynamically change the styles of a component.

In my example that means: I want to receive a prop “color” and then use that in various styles across the component.

Is there any way to do this besides v-bind:style? (Because I have the feeling that using :style in so many places would a) duplicate some logic that I’d want to keep in one place by using a CSS class and b) spread the styling around the <template> where it doesn’t really belong).

So: Did anyone have a similar problem? Is there a sane way to modify the <style> of a single file component (or another DRY enough approach)?

CSS is static. You can’t change a style sheet class declaration etc. dynamically. Single file components can’t change that.

So you have to use style bindings, if simply switching classes for a few pre-determined variations isn’t enough.

(sure, one could in theory dynamically write class definitions into a style tag, but that that sounds horrible)

I know that CSS is static and that writing class definitions dynamically sounds horrible but attaching a [data-v-crypticnumber] to each rule did sound horrible to me as well and still Vue is doing it to great success. :slight_smile:

So expecting to not know everything I asked this. What a pity that CSS is not one of those miraculous things, thanks for pointing it out though.

Anyhow, do you know of any best practices that go into dynamic styling or is the :style property already the way to go?

I just wanted to add how I got to a solution with this:

Since browser compatibility is not an issue for my project, I came to the conclusion to just use CSS variables.

(I already tried that before posting this question but I couldn’t get it to work in Vue-bound style tags, god knows why.)

So as opposed to my opening statement I’m now actually using :style attributes but I’m not spreading them all over my template but I only provide the needed CSS variables with computed values to the root node of the template and then let CSS manage its business.

Thank you anyway for your attention. :slight_smile:

So how exactly are you changing the CSS variables at runtime? I need to solve this problem as well

Pretty much like you change any CSS property in JavaScript: With the .style property of an element.

It’s as easy as element.style.setProperty('--my-variable', 'new-value').

I made you a small JSFiddle to demonstrate that, check it out: https://jsfiddle.net/enbn57jq/

Note that I’ve been using the root element for variables in that example, but you can of course do that equally for any element.

3 Likes

can u use :style tag to update things in that are inside media query? Where 3 will be a dynamic number or something?

   @media (--md-viewport) {
     flex-basis: calc(100%/3);
    }

First, your media query won’t work like this — if --md-viewport is a variable containing a media query, you’d have to use it with the var() function, like this:

@media (var(--md-viewport)) {
  flex-basis: calc(100%/3);
}

Also I assume you’re using the Sass precompiler since your media query does not contain a selector (which is not possible in vanilla CSS).

Now that we’ve clarified this: Yes, you can use the :style property to set CSS variables that are used inside the media query.

Your CSS just needs to replace the 3 with a variable to evaluate, for example var(--divisor):

@media (var(--md-viewport)) {
     flex-basis: calc(100%/var(--divisor));
}

Then you can write your :style property like this:

:style="{ '--divisor': 3 }"

You can now replace the 3 with any reactive data from your component.

1 Like

Thanks for this I managed to acchieve what I had wanted from reading your note, specifically about binding a css variable dynamically to the style element thanks !

thanks Loilo, i think I’ve found a solution to my problem now :slight_smile: