Nuxt.js app from UI kit to deployment. Part 2: Dark theme
We are publishing the second part of a series of articles on creating a modern blog with Nuxt.js. Today we will implement the dark theme in the application that we wrote together with you in the first part.
Note that the code for each part can be found in its own branch at Githuband in master
the version of the application from the last published article is available.
What is dark theme?
Dark theme Is a color scheme for any interface that displays light text and interface elements on a dark background, making it easier to view the screen on mobile phones, tablets, and computers in low light conditions. The dark theme reduces the light emitted from the screen while maintaining the minimum color contrast ratio needed for legibility.
The dark theme improves visual ergonomics by reducing eye strain by adjusting the screen to suit current lighting conditions and providing ease of use at night or in the dark.
Also, keep in mind that using the dark theme in web and mobile applications can extend the battery life of your device. Google confirmedthat dark theme on OLED screens helps a lot to extend battery life.
@ nuxtjs / color-mode
To implement the dark theme, we will use the module @ nuxtjs / color-modewhich provides the following features:
- adds class
.${color}-mode
to the tag<html>
to simplify the management of CSS themes; - works in any mode
Nuxt
(static
,ssr
orspa
); - automatically detects the color mode of the system on the user’s device and can set the appropriate theme based on this data;
- allows you to synchronize the selected theme between tabs and windows;
- allows you to use the implemented themes for individual pages rather than for the entire application (ideal for incremental development);
- the module also supports IE9 + (I’m not sure if this is still relevant in modern development, but it might be useful to someone).
First, let’s install the module:
npm i --save-dev @nuxtjs/color-mode
And then add information about this module to the section buildModules
in file nuxt.config.js
:
{
buildModules: [
'@nuxtjs/color-mode'
]
}
Fine! Now if we run our application and open the tab Elements
in the developer console, we will see that the tag html
added a class that matches the theme of the operating system, for example, in our case class="light-mode"
…
Theme switcher
In the next step, let’s implement a switch that will change the dark theme to the light theme and vice versa.
If you look at design of our application in Figma, then we will see that next to the theme switcher is also a language switcher, which we will implement in one of the next articles in this series.
Let’s immediately write a wrapper component that will encapsulate these switches and be responsible for margins before other components.
To do this, we will create a component AppOptions
with the following content:
<template lang="pug">
section.section
.content
.app-options
switcher-color-mode
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
name: 'AppOptions',
})
</script>
<style lang="scss" scoped>
.app-options {
display: flex;
margin-top: 24px;
}
</style>
Component on Github…
As we can see, there is no logic in this component, it just sets margins for nested components. We now have only one nested component switcher-color-mode
, let’s implement it.
Let’s take a look at the section script
of this component:
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
name: 'SwitcherColorMode',
computed: {
icon() {
return (this as any).$colorMode.value === 'light'
? 'assets/icons/sun.svg'
: 'assets/icons/moon.svg'
},
},
methods: {
changeColorMode() {
;(this as any).$colorMode.preference =
(this as any).$colorMode.value === 'light' ? 'dark' : 'light'
},
},
})
</script>
Here we are implementing the method changeColorMode
which changes theme in the object provided by the module @nuxtjs/color-mode
…
When changing the value $colorMode.preference
the corresponding class of the tag will also be set html
: class="light-mode"
or class="dark-mode"
…
In addition, there is a computed property icon
, which returns the icon we need, depending on the selected theme. Please note that for correct operation you need to add icons sun.svg
and moon.svg
to directory assets/icons
…
The component template will look like this:
<template lang="pug">
button(@click="changeColorMode")
img(
alt="theme-icon"
:src="getDynamicFile(icon)"
)
</template>
Everything is quite simple here! We have a button, when we click on which we call the method changeColorMode
and change our theme. Inside the button, we show an image of the selected theme.
Component on Github…
It remains only to add this component to the main page of our application. After that, the page template should look like this:
<template lang="pug">
.page
section-header(
title="Nuxt blog"
subtitle="The best blog you can find on the global internet"
)
app-options
post-list
</template>
Variable management
As you may remember from the first part, to define all the colors in the application, we used scss
variables, and now all we have to do is change the values of these variables depending on the selected theme.
But the problem is that scss
variables are set once when building the application and we cannot redefine them later when changing the theme.
This limitation can be worked around with js
, but there is a much simpler solution: we can use native css
variables.
Now in our file with variables assets/styles/variables.scss
the section with flowers looks like this:
// colors
$text-primary: rgb(22, 22, 23);
$text-secondary: rgb(110, 109, 122);
$line-color: rgb(231, 231, 233);
$background-color: rgb(243, 243, 244);
$html-background-color: rgb(255, 255, 255);
Let’s first define two color schemes in the same file – light and dark – using css
variables:
:root {
// light theme
--text-primary: rgb(22, 22, 23);
--text-secondary: rgb(110, 109, 122);
--line-color: rgb(231, 231, 233);
--background-color: rgb(243, 243, 244);
--html-background-color: rgb(255, 255, 255);
// dark theme
&.dark-mode {
--text-primary: rgb(250, 250, 250);
--text-secondary: rgb(188, 187, 201);
--line-color: rgb(45, 55, 72);
--background-color: rgb(45, 55, 72);
--html-background-color: rgb(26, 32, 44);
}
}
We defined css
variables in the selector :root
… Standard css
the variable is set and used with a prefix --
…
ABOUT css
pseudo class :root
can be read on MDN and W3Schools… Quote from MDN
:
css
pseudo-class :root
finds the root element of the document tree. Applies to HTML, :root
finds a tag html
and is identical to the selector on the html tag, but its specificity higher.
As we can see, those colors that were previously written directly in scss
variables are now listed in css
variables as default values, and if there is a class .dark-mode
these values are overridden.
Now our scss
variables with colors will look like this:
$text-primary: var(--text-primary);
$text-secondary: var(--text-secondary);
$line-color: var(--line-color);
$background-color: var(--background-color);
$html-background-color: var(--html-background-color);
When switching the theme, the color scheme will change according to the given values and we do not need to change anything in the already implemented components.
Conclusion
Thanks to this article, we learned how to implement a dark theme for a Nuxt.js application.
Did you manage to complete all the steps? Do you think the dark theme is just a hype or is it a necessity? Share your thoughts in the comments.
Links to required materials: