Implementing light and dark mode with switcher (part 2)

13
March, 2024
Marija Ercegovac

Learn how to integrate automatic theme switching on your web page based on the OS preference.

This part aims to get the browser to recognize your operating system's theme preference and remember it the next time you visit the web page.

Technologies used in this article:

Defining light and dark mode style for our web page

Let's start working on the dark mode. We will use color-scheme  property and prefers-color-scheme media query to achieve auto-detection of our operating system's (OS) theme preferences via CSS only.

Our website has light mode as default so we need to define the dark mode style.

color-scheme and prefers-color-scheme are very convenient to use with CSS preprocessor and SCSS mixin. We've created a separate stylesheet mixin.scss and defined custom variables for light and dark modes. Then we imported the  mixin in the stylesheet where the styles for the :root are defined.

mixin.scss:

@mixin light-mode {
  --background: #fff;
  --color: #222;

  color-scheme: light;
}

@mixin dark-mode {
  --background: #222;
  --color: #fff;

  color-scheme: dark;
}

base.scss:

:root {
  @include light-mode;
}

@media (prefers-color-scheme: dark ){
  :root {
    @include dark-mode;
  }
}

Introducing classes for toggle button

We have reached our goal of setting our page to detect users' OS preferences for dark or light mode. But we know that we will be adding the option to change the mode manually later. While toggling the color theme can be done in various ways, we chose to do it by toggling .dark/.light classes via JavaScript (the process is covered in detail in the third part). Adding the .light class can be confusing, but it is necessary if we want to override dark mode manually. The only step left in this part is defining styles under each class for later use in the toggle button.

base.scss:

:root {
  @include light-mode;
}

/* used for toggling modes */
.dark {
  @include dark-mode;
}

@media (prefers-color-scheme: dark ){
  :root {
    @include dark-mode;
  }

  /* used for toggling modes */
  .light {
    @include light-mode;
  }
}

This way we respect the DRY principle, which has a few benefits:

  • the variables are only defined once
  • it is scalable so you can use it with just a few or a few thousand variables
  • if you have to change a variable, you can change it in one place and don't have to go through the whole project, which significantly lowers the risk of mistake or omission and saves time
  • the code is more readable

The caveat to this approach is that while your variables are not repeated in the project's source code, they will be on the compiled CSS.

Now the browser can detect our OS mode preference and our web page will be rendered in the OS preferred mode.

final result of webpage in dark and light mode

To see how to upgrade this and add a switcher for manually toggling dark and light modes, read the third part of the series.

Resources

Light/dark mode info & inspo:

Accessibility: