CSS in Vue.js
23 Oct 2019
CSS Modules in Vue.js
Part three in a series of articles about working with CSS in Vue.js, focusing on using CSS Modules in Vue.js.
In these types of frameworks, it has become popular to use CSS Modules. It is a way of automatically creating unique class names, thereby preventing any possible style leaking or cascading between elements.
Support for CSS Modules is already setup by default by the Vue CLI.
In the .vue file where you want to use CSS modules, add module
to the style tag:
<style module>
.hello{
background-color: mistyrose;
}
</style>
In the .vue file template, the class name is then added though javascript:
<div :class="$style.hello">
The $style
prefix used in .vue file templates refers to any styles within the component (.vue file) style tag.
Targeting Elements Without Class Names
For targeting HTML elements without class names like p or h1, you would have to make sure they are related to their parent for them to be included in the module class name output.
In the example below, the h3 style text-decoration underline will be added to the CSS as .hello-[modulename-identifier] h3. The h3 outside of the .hello block will not be included in the .hello-[modulename-identifier] block and therefore risk affecting other h3 tags outside of the module.
<style module>
.hello{
background-color: mistyrose;
}
.hello h3{
text-decoration: underline;
}
h3{
margin: 1em 0;
}
</style>
Changing the Class Name
If you want to change the generated module class names, this can be done in the vue.config.js file:
module.exports = {
css: {
loaderOptions: {
css: {
localIdentName: '[local][Frida][hash:base64:8]'
// camelCase: 'only' //optional setting for how the name is output
}
}
}
}
In the example above, I’ve added my name Frida
followed by a random string to make sure the name is unique.
Utilizing the Class Name
It is possible to use the expression $style.hello
as a reference to the class name elsewhere within the vue component.
<p>Printing $style.hello: {{ $style.hello }}</p>
The code above will output: “Printing $style.hello: hello-[modulename-identifier]”
This can also be used to for example target the element using JavaScript, access and print out its styles or do any other operation. Because of the module naming convention, the class name acts like an ID meaning there will be just one element with this specific name.
Example: outputting an element style
A very basic example where an element’s background-color is output.
In the .vue file template section:
<p>{{ $style.hello }} background-color is: {{ dataBackground }}</p>
<!-- hello-[modulename-indentifier] background-color is: #ffe4e1 -->
In the .vue file script section:
<script>
export default {
data () {
return {
dataBackground: 'background'
}
},
methods: {
classNameBackground () {
const elem = document.getElementsByClassName(this.$style.hello)[0]
const compStyles = window.getComputedStyle(elem)
const bg = compStyles.getPropertyValue('background-color')
this.dataBackground = bg
return bg
}
},
mounted () {
this.classNameBackground()
}
}
</script>
In the .vue file style section:
<style module>
.hello{
background-color: #ffe4e1;
}
</style>
CSS Modules :export
Another way of accessing information in the CSS style block is to use the :export
feature in CSS Modules to export strings from the style tag:
<template>
<p>{{ $style.primaryColor }}</p>
<!-- Outputs: #ffe4e1 -->
<p>{{ $style.displayAs }}</p>
<!-- Outputs: some-string -->
</template>
<style module lang=”scss”>
$primary-color: #ffe4e1;
:export {
primaryColor: $primary-color;
displayAs: some-string;
}
</style>
Note that the :export
feature seems restricted to working with strings. To get a specific CSS style from a named class, it might be better to go the JavaScript route as per the example above.
Read more about :export
feature in the CSS Modules documentation, and more about CSS Modules in Vue in the vue-loader documentation.
Importing Module Style Files
For when you want to place your CSS Module styles in separate files, rather than in the style tag in each .vue component file.
Create your style file and place it for example in the same folder as your component. Name it “filename.module.fileextension”. In my example, I’ve created the style file “HelloWorld.module.scss”. In HelloWorld.module.scss:
.imported{
background-color:green;
}
Import the style file in the script tag of the component where you want to use it, in this example HelloWorld.vue. I found that I also had to add the import to data:
<script>
import scssStyles from './HelloWorld.module.scss'
export default {
data () {
return {
scssStyles
}
}
}
</script>
In the template part of your component, add the class by referencing the import name and the class name in the style file:
<template>
<p :class="scssStyles.imported">
</template>
Make all CSS Files CSS Modules
If you want to be able to omit the extra “.module” in the file name, you can add this setting to the vue.config.js file:
module.exports = {
css: {
modules: true
}
}
However setting modules to true will at the same time also cause all other style files to be working as CSS modules.
Note that the imported .module.scss file content is not available to the vue file component style tag, since the generated class names will differ. Also note that variables inside the imported file are not available to the component style tag. To achieve this, see the article “Importing Style Files to Component Style Tags in Vue.js”.
Setup info
The starting code for this article is created by the Vue CLI command tool version 3.3.0 and Vue.js version 2.6.10. Note that both setup, plugins and framework are evolving. Changes will in time most certainly happen that make the techniques described in this post less relevant.
Articles in this series
- Part 1: Working with CSS in Vue.js
- Part 2: Adding CSS to a Vue.js Project
- Part 3: CSS Modules in Vue.js
- Part 4: Importing Style Files to Component Style Tags in Vue.js