CSS variables, also known as custom properties, have become a staple for web developers looking to create dynamic and maintainable styles. But what happens when you need to change these variables at runtime? That’s where JavaScript comes in. In this article, we’ll explore how to update CSS variables with JavaScript, using Vue.js as our framework of choice. We'll walk through the concepts and practical steps, providing code snippets to help you apply this to your own projects. By the end, you'll understand how to integrate CSS variables into your Vue components for a seamless, dynamic experience.
CSS variables are essential for writing DRY (Don’t Repeat Yourself) code, especially in complex applications. They allow you to define a value once and reuse it throughout your stylesheets. Whether you're dealing with theme switching, responsive design, or dynamic styling based on user input, CSS variables can handle it.
Here’s a quick example of how CSS variables look:
:root {
--main-color: #42b983;
--text-size: 16px;
}
body {
background-color: var(--main-color);
font-size: var(--text-size);
}
In this case, --main-color
and --text-size
are defined at the root level, making them accessible throughout the entire stylesheet. Now, what if you want to change --main-color
dynamically, based on user interactions or application state? That’s where JavaScript comes in.
JavaScript provides a powerful way to manipulate CSS variables at runtime by interfacing with the DOM's style
property. The document.documentElement (or :root
in CSS) is key here, as it allows you to access and modify global CSS variables. The getComputedStyle method retrieves the current value of a CSS variable, while setProperty updates it.
Here’s how you can access and update a CSS variable using JavaScript:
// Get the root element
const root = document.documentElement;
// Retrieve the current value of a CSS variable
const currentColor = getComputedStyle(root).getPropertyValue('--main-color');
// Update the CSS variable
root.style.setProperty('--main-color', '#ff5733');
This basic approach works in any JavaScript application. But how do we incorporate this into a Vue.js application for a more reactive and maintainable solution?
Vue.js is all about reactivity, making it a perfect fit for dynamically updating CSS variables. In Vue, you can easily integrate this logic within the Vue component lifecycle or bind it to a computed property for seamless updates.
Here’s an example that demonstrates how to update a CSS variable within a Vue component:
<template>
<div>
<button @click="changeColor">Change Theme Color</button>
</div>
</template>
<script setup>
const changeColor = () => {
const root = document.documentElement
root.style.setProperty('--main-color', '#ff5733')
}
</script>
<style>
:root {
--main-color: #42b983;
}
body {
background-color: var(--main-color);
}
</style>
In this example, clicking the button triggers the changeColor
method, which updates the --main-color
CSS variable.
Change CSS Variable in Vue.js at Runtime
The background color of the page will change accordingly.
watch
for Reactive UpdatesTo take things further, you can use Vue.js’ watch API to reactively update CSS variables based on data changes. This is particularly useful when your app's state should control certain styles dynamically, such as in a theme switcher.
Let’s consider we have --main-color
CSS variable in the :root
and we’re using it to set the body color:
:root {
--main-color: #42b983;
}
body {
background-color: var(--main-color);
}
Here’s an enhanced version using Vue.js composition API with script setup
and watch
:
<template>
<div>
<button @click="toggleTheme">Toggle Theme</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const root = document.documentElement
const darkThemeHex = '#333'
const lightThemeHex = '#42b983'
const isDarkTheme = ref(false)
watch(isDarkTheme, (oldValue, newValue) => {
const newColor = newValue ? lightThemeHex : darkThemeHex
root.style.setProperty('--main-color', newColor)
})
const toggleTheme = () => {
isDarkTheme.value = !isDarkTheme.value
}
</script>
Now, every time the isDarkTheme
variable changes, the watch
function is triggered, updating the --main-color
CSS variable accordingly. This pattern is particularly useful in scenarios where themes or other styles need to change dynamically based on application state.
Now that you understand the basics, let's explore some practical use cases where updating CSS variables with JavaScript and Vue.js can significantly improve your application.
As demonstrated earlier, dynamically changing CSS variables is perfect for theme switching. You can store multiple themes as sets of CSS variables, and update them based on user preference. For example, you could switch between light and dark themes, or even offer more granular control over font sizes or color palettes.
Another great use of CSS variables is in responsive design. You can update layout styles based on screen size or device orientation. For instance, changing the spacing or font size for mobile users can be easily achieved by updating CSS variables based on a resize event.
window.addEventListener('resize', () => {
const root = document.documentElement;
const newFontSize = window.innerWidth < 600 ? '14px' : '16px';
root.style.setProperty('--text-size', newFontSize);
});
In this code snippet, the font size adjusts dynamically based on the screen width, ensuring a responsive and user-friendly design.
While updating CSS variables with JavaScript is powerful, it's essential to be mindful of performance. Excessive DOM manipulation can cause layout reflows, especially in large applications. Vue’s reactivity system helps mitigate some of these concerns by ensuring updates are batched and efficient. However, it’s good practice to minimize the number of times you update CSS variables, particularly in scenarios where the changes are triggered by frequently occurring events like scrolling or resizing.
Let’s go through some of the best practices to avoid any negative impact on performance.
When updating multiple CSS variables, grouping them together in a single operation reduces browser reflows and improves performance.
Here’s an example using the Composition API with script setup
to batch CSS variable updates:
<template>
<div>
<button @click="updateVariables">Update Variables</button>
<p>Hello there!</p>
</div>
</template>
<script setup>
const updateVariables = () => {
const root = document.documentElement
// Batch update using cssText
root.style.cssText = `
--main-color: #ff5733;
--text-size: 18px;
--border-radius: 10px;
`
}
</script>
<style>
:root {
--main-color: #42b983;
--text-size: 14px;
}
body {
background-color: var(--main-color);
font-size: var(--text-size);
}
</style>
In this example, the cssText property batches multiple updates to minimize reflows.
When updating CSS variables in response to frequent events like resizing, debounce the updates to improve performance.
Here’s how to debounce a resize
event using the Composition API:
<template>
<p>Resize the window to see the text size change</p>
</template>
<script setup>
import { onMounted, onBeforeUnmount } from 'vue'
let debounceTimeout = null
const updateTextSize = () => {
const newFontSize = window.innerWidth < 600 ? '14px' : '16px'
document.documentElement.style.setProperty('--text-size', newFontSize)
}
const debounceResize = () => {
clearTimeout(debounceTimeout)
debounceTimeout = setTimeout(() => {
updateTextSize()
}, 200)
}
onMounted(() => {
window.addEventListener('resize', debounceResize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', debounceResize)
})
</script>
<style>
:root {
--text-size: 16px;
}
p {
font-size: var(--text-size);
}
</style>
Here, the debounceResize
method ensures that CSS variable updates only happen after the window resizing has stopped, improving performance.
Instead of building our own debounce function, we can use VueUse’s useDebounceFn helper function to achieve the same thing:
<script setup>
import { onMounted, onBeforeUnmount } from 'vue'
import { useDebounceFn } from '@vueuse/core'
const updateTextSize = () => {
const newFontSize = window.innerWidth < 600 ? '14px' : '16px'
document.documentElement.style.setProperty('--text-size', newFontSize)
}
const debounceResize = useDebounceFn(() => {
updateTextSize()
}, 200)
onMounted(() => {
window.addEventListener('resize', debounceResize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', debounceResize)
})
</script>
When possible, limit the scope of your CSS variable updates to specific components instead of applying them globally. This helps keep the impact localized and improves maintainability.
Here’s an example of scoped variable updates within a Vue component:
<template>
<div ref="themeContainer" class="theme-container">
<button @click="changeTheme">Switch Theme</button>
</div>
</template>
<script setup>
import { useTemplateRef } from 'vue'
const container = useTemplateRef('themeContainer')
const changeTheme = () => {
container.value.style.setProperty('--theme-color', '#007bff')
}
</script>
<style scoped>
.theme-container {
--theme-color: #42b983;
width: 100%;
height: 100vh;
background-color: var(--theme-color);
}
button {
color: #fff;
background-color: var(--theme-color);
}
</style>
In this example, the CSS variable --theme-color
is scoped to the .theme-container
, limiting its effect to just that component.
We can even rely on Vue.js’ SFC CSS features instead of defining CSS variables:
<template>
<div class="theme-container">
<button @click="changeTheme">Switch Theme</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const themeColor = ref('#42b983')
const changeTheme = () => {
themeColor.value = '#007bff'
}
</script>
<style scoped>
.theme-container {
width: 100%;
height: 100vh;
background-color: v-bind(themeColor);
}
button {
color: #fff;
background-color: v-bind(themeColor);
}
</style>
In this example, we didn’t have to define a CSS variable. Instead, we defined a themeColor
variable ref and used v-bind() in CSS to bind its value to the corresponding CSS property.
Updating CSS variables with JavaScript, especially within a Vue.js application, offers a powerful way to create dynamic and responsive UIs. Whether you're implementing theme switching, adjusting styles for responsiveness, or reacting to user input, combining CSS variables with Vue’s reactivity opens up a world of possibilities.
Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.
More than 200.000 users have already joined us. You are welcome too!
© All rights reserved. Made with ❤️ by BitterBrains, Inc.