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 .
Please note that the code for each part can be found in its own thread on Github , and the
master
version of the application from the last published article is available.
What is dark theme?
A dark theme is a color scheme for any interface that displays light text and interface elements against 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 has confirmed that the dark theme on OLED screens is very helpful in extending battery life.
@ nuxtjs / color-mode
To implement the dark theme, we will use the @ nuxtjs / color-mode module , which provides the following capabilities:
- Adds a class
.${color}-mode
to the tag<html>
to make it easier to manage 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 the file
nuxt.config.js
:
{
buildModules: [
'@nuxtjs/color-mode'
]
}
Fine! Now, if we run our application and open a tab
Elements
in the developer console, we will see that
html
a class has been added to the tag that corresponds to the operating system theme, 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 we look at the design of our application in Figma, we can 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, 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. Now we have only one nested component
switcher-color-mode
, let's implement it.
Let's take a look at the section of
script
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 a method
changeColorMode
that changes theme in the object provided by the module
@nuxtjs/color-mode
.
When the value is changed
$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
that returns the icon we need, depending on the selected theme. Please note that in order to work correctly you need to add icons
sun.svg
and
moon.svg
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 a 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, we used
scss
variables to define all the colors in the application , and now all we have to do is change the values ββof these variables depending on the chosen theme.
But the problem is that the
scss
variables are set once when building the application, and in the future we cannot redefine them when changing the theme.
This limitation can be circumvented using
js
, but there is a much simpler solution: we can use native
css
variables.
Now in our file with variables, the
assets/styles/variables.scss
section with colors 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 have defined the
css
variables in the selector
:root
. By standard, a
css
variable is specified and used with a prefix
--
. Read
about
css
pseudo- class
:root
on MDN and W3Schools . Quote from
MDN
: The
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 html tag selector, but its specificity is higher.
As we can see, those colors that were previously written directly in
scss
variables are now specified in
css
variables as default values, and if a class is present,
.dark-mode
these values ββare overridden.
Now our
scss
color variables 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: