33

Is it possible to use pure CSS variables with Vue without having to link any stylesheets or use SASS/PostCSS? Unsure why I'm unable to get this to work in its most basic form.

<template>
   <div id="test">
        TEST
    </div>
</template> 
<style scoped> 
   :root {
   --var-txt-color: #c1d32f;
   }

 #test {
 color: var(--var-txt-color);
  }
</style> 
3
  • 1
    what if you use something else than :root? try body or a container element Commented Nov 10, 2018 at 14:49
  • I just tried using a body tag but that did not work. Could it be that because its a component and not on the main App.vue causes it to not understand the :root? This is the component in particular I'm trying to get to work on: github.com/bencasalino/nba-timeline-project/blob/master/src/… Commented Nov 10, 2018 at 14:57
  • 1
    I don't know as I know CSS variable but not experienced with Vue.js ... if you are able to give a link with the working app I can help you by looking at the generated code Commented Nov 10, 2018 at 15:03

6 Answers 6

42

I know you highlighted "without having to link any stylesheet", but I run into the same issue and there is a simple option - use just one external css file and include it in your App.vue, then you can access the variables anywhere else, in scoped styles as well.

variables.css

:root {
  --font-family: "Roboto", "Helvetica", "Arial", sans-serif;
  --primary-color: #333a4b;
}

App.vue

<style>
  @import './assets/styles/variables.css';
</style>

LandingView.vue

<style scoped>
  #landing-view {
    font-family: var(--font-family);
    font-weight: 300;
    line-height: 1.5em;
    color: var(--primary-color);
  }
</style>
Sign up to request clarification or add additional context in comments.

2 Comments

Would you be able to somehow access the css variables in the script tag too? or vice versa?
This is by far the cleanest solution I have found for this problem. Good job.
33

This won't work as expected because of scoped attribute for stylesheet. Example above compiles into:

[data-v-4cc5a608]:root {
  --var-txt-color: #f00;
}

And, as you understand, it will not target actual :root element.

It can be solved by:

  • Not using scoped attribute for this stylesheet. Notice that it may cause styles conflict with other variables declarations for :root element.

  • Using current component's wrapping element as root. If we declare variables this way:

    .test {
      --var-txt-color: #c1d32f;
      color: var(--var-txt-color);
    }
    
    .test-child-node {
      background-color: var(--var-txt-color);
    }
    

Then it will can reuse variables for other elements of the same component. But still, it won't be possible to use declared variables inside child components without removing scoped, if it is the case.

1 Comment

Ended up using SASS, but the fact that its 'scoped' makes sense on why its not working, thank you so much!
15

Why not just use this?

<style scoped>
  * {
    --var-txt-color: #c1d32f;
  }
</style>

The generated CSS is:

*[data-v-d235d782] {
  --var-txt-color: #c1d32f;
}

This has been working for me.

I just discovered that it looks like this also works, using the "deep selector"

>>>  {
  --var-txt-color: #c1d32f;
}

Generated CSS is:

[data-v-d235d782] {
  --var-txt-color: #c1d32f;
}

I think I like this method more.

2 Comments

thx. I like this way. simple and variables are available within my component.
Worked beautifully for me
6

One workaround is to define them under a non-scoped style element like the following. However one thing to note here is, these variables will be exposed to other Vue components as well.

<style>
  :root {
     --var-txt-color: #c1d32f;
  }
</style>

<style scoped>
  #test {
     color: var(--var-txt-color);
  }
</style> 

Comments

6

Well, now you can use CSS variable injection.

<template>
  <div>
    <div class="text">hello</div>
  </div>
</template>

<script>
  export default {
    data() {
        return {
            color: 'red',
            font: {
                weight: '800'
            }
        }
    }
  }
</script>

<style>
  .text {
    color: v-bind(color);
    font-weight: v-bind('font.weight');
  }
</style>

Those styles are also both reactive and scoped. There won't be any unintended inheritance issues. Vue manages the CSS variables for you.

You can take a look at the RFC here.

Comments

6

Late answer - Here is a working example with css vars derived from standard vue structures.

<template>
  <div>
  <component :is="'style'">
    :root {
    --color: {{ color }};
    --text-decoration: {{ textDecoration }};
    --font-size: {{ fontSize }};
    }
  </component>
    <p>example</p>
  </div>
</template>

<script>

export default {

  props:{
    color: {
      type: String,
      default: '#990000'
    }
  },

  data: function () {
    return {
      textDecoration: 'underline'
    }
  },

  computed: {
    fontSize: function (){
      return Math.round(Math.random() * (5 - 1) + 1) + 'em';
    }
  }
}
</script>

<style>
p{
  color: var(--color);
  text-decoration: var(--text-decoration);
  font-size: var(--font-size);
}
</style>

Starting from the top...

  • Vue must have 1 root element, so I needed a div tag in order to include a sample p tag. However, you can just use the component-is-style tag and get rid of the div and p tags. Note the need for extra quotations "'style'".
  • The normal vue style tag can be scoped or not - as needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.