Nuxtstop

For all things nuxt.js

Adding a dark mode to your website using SCSS

Adding a dark mode to your website using SCSS
23 1

Most developers are using and loving it for years. After the release of iOS 13 it was introduced to people outside the development bubble.
The ✨dark mode✨.

For a long time I wanted my own website to feature a dark mode. So I started gathering my own requirements for that feature.

It should be working with my current setup of using SCSS and the colors defined within it. Also, the site should detect the preferred color-scheme and initialize that way. Lastly, you should always be able to switch the color-scheme independent of your preferred scheme.

So let's get started:

Step 1: Creating color-schemes

In my setup, the colors are already defined in a single SCSS file like this. All the other files are referencing these colors by name.

$onyx: #404040;
$cultured: #f5f5f5;
...
Enter fullscreen mode Exit fullscreen mode

Since these colors are static, we need to transform them into CSS variables which are globally accessible. This way we can switch out the value of the colors which are referenced.

// creating a light and a dark theme on html level
html[data-theme="light"] {
  --color-text: #{$onyx};
  --color-background: #{$cultured};
}

html[data-theme="dark"] {
  --color-text: #{$cultured};
  --color-background: #{$onyx};
}
Enter fullscreen mode Exit fullscreen mode

You can see in the light theme, we are using the dark text-color with a light background. And it is reversed in the dark theme.

The last step to set up the color-scheme is to reference the CSS variables where they are needed.

color: var(--color-text);
background: var(--color-background);
Enter fullscreen mode Exit fullscreen mode

Now we need to add this data-theme attribute used in the scheme definition to the html tag.

Step 2: Add the attribute

To add the attribute we can use this short JS line.

document.documentElement.setAttribute('data-theme', 'dark');
Enter fullscreen mode Exit fullscreen mode

With only this line, we would always be seeing the dark theme.

But we can dynamically set the attribute based on this checkbox.

<input type="checkbox" name="theme_switch"/>
Enter fullscreen mode Exit fullscreen mode
// switch theme if checkbox is engaged
document.querySelector('input[name=theme_switch]')
    .addEventListener('change', (cb) => {
      document.documentElement.setAttribute(
        'data-theme',
        cb.target.checked ? 'dark' : 'light'
      );
Enter fullscreen mode Exit fullscreen mode

Now, the checkbox actually switches the data-theme attribute. And the attribute switches the CSS variables.

Step 3: Initialize with the preferred theme

The final step is to initialize the data-theme during the first load with the preferred theme.
To find out which theme is preferred by the user, we can use the following condition:

window.matchMedia('(prefers-color-scheme: dark)').matches
Enter fullscreen mode Exit fullscreen mode

This returns true if the preferred theme is dark.
Now we add all together:

let checkbox = document.querySelector('input[name=theme_switch]');

if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  document.documentElement.setAttribute('data-theme', 'dark');
  checkbox.checked = true;
} else {
  document.documentElement.setAttribute('data-theme', 'light');
  checkbox.checked = false;
}

// switch theme if checkbox is engaged
checkbox.addEventListener('change', (cb) => {
  document.documentElement.setAttribute(
    'data-theme',
    cb.target.checked ? 'dark' : 'light'
  );
});
Enter fullscreen mode Exit fullscreen mode

Final Feature

Here is the working CodePen of the work we did today. In the next part, we are going to style this checkbox to feel like an actual toggle.