Reputation: 1179
Is it possible to add the dynamic variable in style?
I mean something like:
<style>
.class_name {
background-image({{project.background}});
}
@media all and (-webkit-min-device-pixel-ratio : 1.5),
all and (-o-min-device-pixel-ratio: 3/2),
all and (min--moz-device-pixel-ratio: 1.5),
all and (min-device-pixel-ratio: 1.5) {
.class_name {
background-image({{project.background_retina}});
}
}
</style>
Upvotes: 98
Views: 220640
Reputation: 25
In Vue 3, you can do conditions in your css via v-bind
too. Like
<script>
data() {
return {
hasColor: true
};
}
</script>
<style scoped lang="scss">
.class-name {
background-color: v-bind('!hasColor ? "blue" : "red"');
}
</style>
Tested it with "vue": "^3.2.37"
Upvotes: 0
Reputation: 4617
With Vue.js 3.2 you can do State-Driven Dynamic CSS like this:
<template>
<h1 id="script">Script</h1>
<h1 id="scriptSetup">Script setup</h1>
</template>
<script>
export default {
data() {
return {
colorFromScript: 'red'
}
}
}
</script>
<script setup>
const colorFromScriptSetup = 'green'
</script>
<style>
#script {
color: v-bind('colorFromScript')
}
#scriptSetup {
color: v-bind('colorFromScriptSetup')
}
</style>
Upvotes: 95
Reputation: 143284
I was able to embed multiple CSS rules when using progressive Vue.js (i.e. no npm / build step) using Vue's dynamic <component>
:
const MyComponent = {
template:`<div>
<component is="style" v-html="css"></component>
</div>`,
setup() {
const css = `
.animation-pulse {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
transform: scale(0.8);
box-shadow: 0 0 0 0 rgba(229, 62, 62, 1);
}
70% {
transform: scale(1);
box-shadow: 0 0 0 60px rgba(229, 62, 62, 0);
}
100% {
transform: scale(0.8);
}
}`
return { css }
}
}
Upvotes: 0
Reputation: 369
This works for me - if you add the style tags along with the definitions and it should work.
<template>
<div class="wrap">
<div v-html="customStyle"></div>
</div>
</template>
<script setup>
import { ref } from "vue";
const customStyle = ref("<style>body{background:blue!important;}</style>");
</script>
Upvotes: 0
Reputation: 3618
This is simple to do, even better if already using a framework / css variables.
By adding style to your html that would overwrite the root/variables according to loaded "dynamic css"
In that case using css vars in your css
<style>
.myTheme{
color:var(--theme-color)
}
</style>
then having a computed property like:
computed:{
accountTheme(){
return {"--theme-color":this.themeColor}
}
}
Then whatever method that would change such dynamic theme you do it
methods:{
load(){
....
this.themeColor="red"
}
}
Apply that dynamic style to html element
<html :style="accountTheme"></html>
Upvotes: 0
Reputation: 10502
I liked @mickey-mullin reply, but not everything worked entirely. The url
missed require
, even though the information in his post helped me a lot in my case.
var()
, url()
, multiple ternary operators (my own case - you shouldn't need it), I was able to do so for background-image
in such a way:
template
<div :style="[
case1 ? { '--iconUrl': `url(${require('../../../public/icon1.svg')})`} :
case2 ? { '--iconUrl': `url(${require('../../../public/icon2.svg')})`} :
{ '--iconUrl': `url(${require('../../../public/default.svg')})` },
]" class="myClass">
styles
div.myClass::before {
background-image: var(--iconUrl);
}
Note: I didn't have to declare iconUrl
in my data()
-> return
.
Upvotes: 0
Reputation: 71
I needed to write completely dynamic styles, so I used approach beyond Vue system:
{
// Other properties.
watch: {
myProp: {
handler() {
this.styleElement.innerHTML = this.myProp.css;
},
deep: true,
},
},
mounted() {
this.styleElement = this.document.createElement('style');
this.styleElement.innerText = this.myProp.css;
this.document.head.append(this.styleElement);
},
unmounted() {
this.styleElement.remove();
},
}
Though it may have some performace issues with CSS big enough.
Upvotes: 1
Reputation: 1975
I know this is a bit late and is using Vue.js 2, but as of now in Vue.js 3 you can create state-driven CSS variables.
You can now use your SFC (Single File Component) state data inside your styles tags using v-bind()
.
You can read more about state-driven CSS variables here, or read the Vue.js 3 documentation here.
Here is a code example
<template>
<div>
<input type="text" v-model="color" />
<div class="user-input-color">
{{ color }}
</div>
</div>
</template>
<script>
export default {
data: () => ({
color: 'white'
})
}
</script>
<style scoped>
.user-input-color {
background-color: v-bind(color)
}
</style>
Here is a link to the live example.
Links
Upvotes: 6
Reputation: 1130
You can use the component tag offered by Vue.js.
<template>
<component :is="`style`">
.cg {color: {{color}};}
</component>
<p class="cg">I am green</p> <br/>
<button @click="change">change</button>
</template>
<script>
export default {
data(){
return { color: 'green' }
},
methods: {
change() {this.color = 'red';}
}
}
</script>
Upvotes: 5
Reputation: 2881
I encountered the same problem and I figured out a hack which suits my needs (and maybe yours).
As <style>
is contained in <head>
, there is a way to make it work:
We generate the CSS content as a computed property based on the state of the page/component
computed: {
css() {
return `<style type="text/css">
.bg {
background: ${this.bg_color_string};
}</style>`
}
}
Now, we have our style as a string and the only challenge is to pass it to the browser.
I added this to my <head>
<style id="customStyle"></style>
Then I call the setInterval
once the page is loaded.
mounted() {
setInterval(() => this.refreshHead(), 1000);
}
And I define the refreshHead as such:
methods: {
refreshHead() {
document.getElementById('customStyle').innerHTML = this.css
}
}
Upvotes: 2
Reputation: 934
In simple terms, this is how you would do it in Vue.js and Nuxt.js:
<template>
<div>
<img :src="dynamicImageURL" alt="" :style="'background-color':backgroundColor"/>
</div>
</template>
<script>
export default{
data(){
return {
dynamicImageURL='myimage.png',
backgroundColor='red',
}
}
}
</script>
Upvotes: 0
Reputation: 1946
Yes, this is possible. Vue.js does not support style
tags in templates, but you can get around this by using a component
tag. Untested pseudocode:
In your template:
<component type="style" v-html="style"></component>
In your script:
props: {
color: String
}
computed: {
style() {
return `.myJSGeneratedStyle { color: ${this.color} }`;
}
}
There are lots of reasons why you shouldn't use this method. It's definitely hacky and :style=""
is probably better most of the time, but for your problem with media queries I think this is a good solution.
Upvotes: 9
Reputation: 851
I faced the same problem. I have been trying to use a background color value from a database. I find out a good solution to add a background color value on inline CSS which value I set from database.
<img :src="/Imagesource.jpg" alt="" :style="{'background-color':Your_Variable_Name}">
Upvotes: 69
Reputation: 17900
CSS <style>
is static. I don't think you can do that... you might have to look for a different approach.
You can try using CSS variables. For example, (the code below is not tested)
<template>
<div class="class_name" :style="{'--bkgImage': 'url(' + project.background + ')', '--bkgImageMobile': 'url(' + project.backgroundRetina + ')'}">
</div>
</template>
<style>
.class_name{
background-image: var(--bkgImage);
}
@media all and (-webkit-min-device-pixel-ratio : 1.5),
all and (-o-min-device-pixel-ratio: 3/2),
all and (min--moz-device-pixel-ratio: 1.5),
all and (min-device-pixel-ratio: 1.5) {
.class_name {
background-image: var(--bkgImageMobile);
}
}
</style>
Note: Only the latest browsers support CSS variables.
If you still see any issues with the :style
in the template then try this,
<div :style="'--bkgImage: url(' + project.background + '); --bkgImageMobile: url(' + project.backgroundRetina + ')'">
</div>
Upvotes: 18
Reputation: 34914
As you are using Vue.js, use Vue.js to change the background, instead of CSS:
var vm = new Vue({
el: '#vue-instance',
data: {
rows: [
{value: 'green'},
{value: 'red'},
{value: 'blue'},
],
item:""
},
methods:{
onTimeSlotClick: function(item){
console.log(item);
document.querySelector(".dynamic").style.background = item;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.js"></script>
<div id="vue-instance">
<select class="form-control" v-model="item" v-on:change="onTimeSlotClick(item)">
<option value="">Select</option>
<option v-for="row in rows">
{{row.value}}
</option>
</select>
<div class='dynamic'>VALUE</div>
<br/><br/>
<div :style="{ background: item}">Another</div>
</div>
Upvotes: 10
Reputation: 599
The best way to include dynamic styles is to use CSS variables. To avoid inline styles while gaining the benefit (or necessity—e.g., user-defined colors within a data payload) of dynamic styling, use a <style>
tag inside of the <template>
(so that values can be inserted by Vue). Use a :root
pseudo-class to contain the variables so that they are accessible across the CSS scope of the application.
Note that some CSS values, like url()
cannot be interpolated, so they need to be complete variables.
Example (Nuxt .vue
with ES6/ES2015 syntax):
<template>
<div>
<style>
:root {
--accent-color: {{ accentColor }};
--hero-image: url('{{ heroImage }}');
}
</style>
<div class="punchy">
<h1>Pow.</h1>
</div>
</div>
</template>
<script>
export default {
data() { return {
accentColor: '#f00',
heroImage: 'https://vuejs.org/images/logo.png',
}},
}
</script>
<style>
.punchy {
background-image: var(--hero-image);
border: 4px solid var(--accent-color);
display: inline-block;
width: 250px; height: 250px;
}
h1 {
color: var(--accent-color);
}
</style>
Also created an alternate more involved runnable example on Codepen.
Upvotes: 42