Mastering the Dark and Light: Using CSS Variables for a Dark Mode Toggle
Published: 2023-09-13 21:22:15

Dark Mode is probably nothing new to you. This eye-pleasing feature not only enhances user experience but also adds a touch of modernity and sophistication to websites. I recently explored the basics of implementing the framework to deploy a light/dark mode toggle from scratch. I had wondered how to seamlessly switch between light and dark modes on a web page, and I found what I was looking for in a very informative post by [pqina](https://pqina.nl/blog/css-colors-with-custom-properties).

Here, I explore a simple yet effective method to toggle between light and dark modes using CSS variables and a bit of JavaScript. While this example is only a barebones structure, the basic process can be expanded to more complex usage.

Check out [the CodePen](https://codepen.io/mammolastan/pen/xxmrWgK) for the complete example.

### Media Query

When I started to implement, I adopted the method of setting the default styling of the web page to be light mode, and then identifying a dark mode preference through a nifty media query [prefers-color-scheme.
](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme)

```css
/* Set variables for base default (light mode) colors */
html {
  --foreground: 40, 30, 220; /* dark blue*/
  --background: 245, 245, 245; /* light  */
}

/* Set variables for base dark mode colors  */
@media (prefers-color-scheme: dark) {
  html[data-theme="dark"] {
    --foreground: 205, 205, 255;
    --background: 40, 30, 220;
  }
}

```
Using this styling, my font color will be the foreground, and of course the background will be the background color. For an intermediate background color for the section, the foreground color is used with an alpha shift applied. 

```css
html {
  color: rgb(var(--foreground));
  background: rgb(var(--background));
}
.panel {
  background: rgba(var(--foreground), 0.25);
}
```
This works just fine - by default, dark text is on a light background, and vice-versa for dark mode. If your device is broadcasting a preference for dark mode, you'll get just that. 



**Light mode**
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l80hvrh2b4k3mzgq9ewi.png" width="200"/>
**Dark mode**
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hlo9k3vbtemy5nf1x23.png" width="200"/>

But even though your device preference might be dark mode, what if you want to view this particular page in its default styling? We need some user interaction - enter, Javascript. 

### Preference selection using Javascript
So, what we need is a method of identifying a preference selection of light or dark, plus a method of changing the page styles. Since the previously used media query is simply a one-time check for the page - if the device requests dark mode, it's applied and that's all there is to it - we need to abandon that. 

In place of the media query, I am taking advantage of the _cascading_ aspect of CSS. For the updated CSS structure, I will set the default CSS color variables in the HTML element, and then set the dark mode variables in that same element with an attribute selector. 

```css
html {
  --foreground: 40, 30, 220; /* dark blue*/
  --background: 245, 245, 245; /* light  */
}

html[data-theme="dark"] {
  --foreground: 205, 205, 255;
  --background: 40, 30, 220;
}
```
Now, our page colors will change when the HTML element has the attribute of _data-theme="dark"_ applied to it. This means that all we need to do now is make the Javascript that will apply that attribute change. 

Upon page load, we can use Javascript to check if this device prefers a dark mode (same as the CSS media query) and apply that choice using a local storage variable. 

```javascript
//pre-check the dark-theme checkbox if dark-theme is set
      if (document.documentElement.getAttribute("data-theme") == "dark") {
toggleSwitch.checked = true;
document.documentElement.setAttribute("data-theme", "dark");
localStorage.setItem("theme", "dark");

      }
```

And we create a toggle that controls the action to switch back and forth. As the toggle changes selection, the data-theme attribute is adjusted, and the local storage variable is changed. 

Review the Code Pen for all the specifics around this activity