Styling Components
When using Vue components, the webpack compiler allows you to use almost any frontend templating language style you prefer. For example, there are several ways to compose CSS, either directly or with pre-processing. The easiest way to enable these expressive languages in your Vue templates is to install them when you set up your project ahead of time using the Vue CLI.
When using the style
tag inside of a Vue component, you have the option to specify a language, provided you have installed the appropriate webpack loader. In Exercise 1.01
, if you chose to install the SCSS preprocessor, you can add the lang="scss"
attribute to the style
tag to begin using SCSS.
For example, if you chose to install the Stylus preprocessor, you can add the lang="stylus"
attribute to the style
tag to begin using Stylus:
<style lang="stylus"> ul color: #2c3e50; > h2 color: #22cc33; </style>
Vue scoping is a handy way to stop individual components from inheriting styles from the virtual DOM head. Add the scoped attribute to your style
tag and write some component-specific styles that will override any other CSS rules from the global sheet. The general rule is to not scope global styles. A common method for defining global styling is to separate these styles into another style sheet and import them into your App.vue
.
Exercise 1.03: Importing SCSS into a Scoped Component
In this exercise, we will be utilizing the style
tag to add SCSS preprocessed styles to a component and importing external stylesheets.
To access the code files for this exercise, refer to https://packt.live/3nBBZyl.
- Open a command-line terminal and navigate into the
Exercise1.03
folder and run the following commands in order:> cd Exercise1.03/ > code . > yarn > yarn serve
Go to
https://localhost:8080
. - Inside of the exercise file, let's write some HTML that can be styled using SCSS. Let's keep practicing the interpolation method:
// src/components/Exercise1-03.vue <template> <div> <h1>{{ title }}</h1> <h2>{{ subtitle }}</h2> <ul> <li>{{ items[0] }}</li> <li>{{ items[1] }}</li> <li>{{ items[2] }}</li> </ul> </div> </template> <script> export default { data() { return { title: 'My list component!', subtitle: 'Vue JS basics', items: ['Item 1', 'Item 2', 'Item 3'] } }, } </script>
- Add the
lang
property to thestyle
tag and add the valuescss
to enable SCSS syntax inside thestyle
block:<style lang="scss"></style>
- Create a folder inside the
src/
directory calledstyles
. Inside this new folder create a file calledtypography.scss
:src/styles/typography.scss
- Inside
typography.scss
, add some styling for the template you composed in your component:/* typography.scss */ $color-green: #4fc08d; $color-grey: #2c3e50; $color-blue: #003366; h1 { margin-top: 60px; text-align: center; color: $color-grey; + h2 { text-align: center; color: $color-green; } } ul { display: block; margin: 0 auto; max-width: 400px; padding: 30px; border: 1px solid rgba(0,0,0,0.25); > li { color: $color-grey; margin-bottom: 4px; } }
Note
In SCSS, you can use standard CSS selectors to select elements in your component.
ul > li
will select every<li>
element inside of a<ul>
element for styling. Similarly, using the addition symbol+
means the elements placed after the first element will be styled if they match the condition. For example,h1 + h2
will dictate that allH2
elements afterH1
will be styled in a way, butH3
will not. You can understand this better through the following example.In CSS, you would present this code as follows:
h1 + h2 { /* Add styling */ } ul > li { /* Add styling */ }
In SCSS, the same code can be represented as follows:
h1 { + h2 { // Add styling } } ul { > li { // Add styling } }
- In your component, import these styles by using the SCSS
@import
method:<style lang="scss"> @import '../styles/typography'; </style>
This will generate an output as follows:
- Add the
scoped
attribute to your<style>
tag to only apply these styles to this component instance. Use the variable from the imported stylesheet$color-blue
:<style lang="scss" scoped> @import '../styles/typography'; h1 { font-size: 50px; color: $color-blue; // Use variables from imported stylesheets } </style>
The output of the preceding code is as follows:
Inspect the DOM and you will notice that at run-time, that scoping has applied
v-data-*
attributes to your DOM elements specifying these specific rules. Ourtypography.scss
, which we are scoping to our component, references an HTML tag that does not live within the scope of our component. When Vue adds data attributes to the scoped component, it generates the style if the<body>
tag exists within the component. In our case, it does not.The
Elements
tab of your browser dev tools will show the following after expanding the<head>
and<style>
tags: - Create a new style sheet called
global.scss
in thestyles
folder:/* /src/styles/global.scss */ body { font-family: 'Avenir', Helvetica, Arial, sans-serif; margin: 0; }
- Import this stylesheet into your
App.vue
:<style lang="scss"> @import './styles/global'; </style>
Our app should now be back to normal, with a mixture of globally defined styling and properly scoped styles for this component, as follows:
In this exercise, we interpolated data that originated from an array, then styled our component using forms of scoped SCSS, which can both exist inside the <style>
tag or be imported from another directory in our project.