Adding a dark mode to your website using SCSS
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;
...
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};
}
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);
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');
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"/>
// 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'
);
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
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'
);
});
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.