DEV Community

Cover image for Dark mode. How to create your first Nuxt.js app (Part 2)
Hostman
Hostman

Posted on

Dark mode. How to create your first Nuxt.js app (Part 2)

This is the second post in our series of articles about creating a modern blog with Nuxt.js. In the previous post we have created our Nuxt.js application and then deployed it to Hostman.

Here we will implement a dark mode for this application.

Please note you can find code for each post in its own branch on Github. The app version from the latest published article is available in master.

Dark mode. What is it?

Dark mode is a color scheme for any interface that displays light text and interface elements against a dark background. This makes it easier to look at the screen of phones, tablets, and computers under low light conditions. The dark theme reduces the light emitted from the screen but maintains the minimum color contrast ratio needed for legibility.

The dark theme improves visual ergonomics and reduces eyestrain by adjusting the screen with current lighting conditions and providing ease of use at night or in darkness.

Furthermore, keep in mind that using the dark theme in web and mobile applications can extend the lifespan of your device battery. Google has confirmed the dark theme on OLED displays is very helpful in prolonging battery life.

@nuxtjs/color-mode

To implement the dark theme, we will use the @nuxtjs/color-mode module, which provides the following possibilities:

  • Add .${color}-mode class to the <html> tag to simplify CSS theme management,

  • Works in any Nuxt mode (static, ssr or spa),

  • Automatically detects the system color mode on the user's device and can set the appropriate theme based on this data,

  • Allows to synchronize the selected theme between tabs and windows,

  • Allows to use the implemented themes for individual pages, not for the whole application (perfect for incremental development),

  • It also supports IE9 + (I'm not sure if this is still relevant in modern development, but it might be useful for someone).

Firstly, let's install the module:

npm i --save-dev @nuxtjs/color-mode`
Enter fullscreen mode Exit fullscreen mode

Then add information about this module to the buildModules section in the nuxt.config.js file:

{
  buildModules: [
    '@nuxtjs/color-mode'
  ]
}
Enter fullscreen mode Exit fullscreen mode

Great! Now if we run our application and open the Elements tab in the developer's console, we will see that a class that matches the operating system theme has been added to the html tag.

For example, in my case, class="light-mode".

Dark and Light Theme switcher

Let's now implement a switcher that will change the dark theme to the light theme and vice versa.

According to the design of our application, there is a language switcher next to the theme switcher. We will cover it in our next posts here.

Let's start with creating a wrapper component that will encapsulate these switchers and will be responsible for margin from other components.

To do this, let's create an AppOptions component 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>
Enter fullscreen mode Exit fullscreen mode

Component on Github.

As we can see, there is no logic in this component and it just sets margins for nested components. Now we have only one nested switcher-color-mode component, let's implement it.

Let's take a look at the script section 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>
Enter fullscreen mode Exit fullscreen mode

Here we implement a changeColorMode method that changes the theme in the object provided by the @nuxtjs/color-mode module.

When the value of $colorMode.preference is changed, the corresponding class of the html tag will also be set: class="light-mode" or class="dark-mode".

There is also a computed property icon that returns the icon we need, depending on the selected theme. Please note that to work correctly, you need to add the sun.svg and moon.svg icons to the assets/icons directory.

The component template looks like this:

<template lang="pug">
button(@click="changeColorMode")
  img(
    alt="theme-icon"
    :src="getDynamicFile(icon)"
  )
</template>
Enter fullscreen mode Exit fullscreen mode

This is quite easy now! There is a button. Clicking on it we call the changeColorMode method and change our theme. Inside the button, we show an image of the selected theme.

Component on Github.

What we have to do is add this component to the main page of our application. After this step 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>
Enter fullscreen mode Exit fullscreen mode

Variables management

As you know from the first part, we used scss variables to define all the colors in the application. Now we should change the values ​​of these variables depending on the selected theme.

But the real problem is that scss variables are set once when building the application and later we cannot override them when changing the theme.

This limitation can be bypassed using js, but it would be much easier if we use native css variables.

Now in our file with variables assets/styles/variables.scss, the 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);
Enter fullscreen mode Exit fullscreen mode

Let's define two color schemes in this 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);  
  }  
}
Enter fullscreen mode Exit fullscreen mode

We have defined CSS variables in the :root selector. According to the CSS standard, a variable is specified and used with the prefix --.

Read about the CSS pseudo-class :root on MDN and W3Schools.

“The CSS pseudo-class :root finds the root element of the document tree. Applies to HTML, :root finds the html tag and is identical to the selector html, but its specificity is higher”.
Source: MDN.

Those colors that were previously defined directly into SCSS variables are now specified in css variables as default values, and if the .dark-mode class is present, 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);
Enter fullscreen mode Exit fullscreen mode

Now, when switching a theme, our color scheme will change according to the specified values ​​and we do not need to change anything in the already implemented components. The file with styles on Github.

Conclusion

Here we learned how to implement dark mode for Nuxt.js application. Are you going to follow our steps? Is dark mode just overrated and overhyped or necessity and benefit? Please share your thoughts below. What do you think?

Later in our blog here we will discuss such topics as:

  • multilingual applications,
  • PWA and SEO, including Sitemap auto-generation and robots.txt,
  • setting up Analytics (Google and Yandex) and bug tracker (Sentry),
  • application optimization for passing tests Lighthouse /PageSpeed.

Top comments (2)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.