I was looking for a simple way to implement dark/light mode on my site and have settled on this method as of right now:
Setting a data attribute on the body that contains the current theme
<body name="body" theme="dark">
A JavaScript function to swap between the themes:
let themeToggle = document.getElementById("theme-toggle")
let body = document.getElementsByName("body").item(0)
let currentTheme = body.getAttribute("theme")
function toggleTheme() {
currentTheme = (currentTheme == "dark") ? "light" : "dark"
body.setAttribute("theme", currentTheme)
}
With the current approach I am currently splitting my CSS into multiple CSS/SCSS files, a layout one (syle.scss
), a dark.scss
, a light.scss
and a _colors.scss
.
However, with this I end up with two very similar SCSS files like this:
dark.scss:
@use 'colors' as c;
body[theme="dark"] {
background-color: c.$dark-background;
#theme-toggle {
border-color: c.$light-background;
}
div {
background-color: c.$dark-accent;
}
}
light.scss:
@use 'colors' as c;
body[theme="light"] {
background-color: c.$light-background;
#theme-toggle {
border-color: c.$dark-background;
}
div {
background-color: c.$light-accent;
}
}
Now I am wondering if there was a possibility to do something like this:
body {
$activeTheme: attr(theme);
@if $activeTheme == "dark" {
$inactiveTheme: "light";
} @else {
$inactiveTheme: "dark";
}
background-color: c.{$activeTheme}-background;
#theme-toggle {
border-color: c.{$inactiveTheme}-background;
}
div {
background-color: c.{$activeTheme}-accent;
}
}
I have tried to use interpolation, but I can't quite get it to work.
It's not possible to use Sass in this way. Sass is compiled to CSS before it is sent client-side, so by the time it's in a user's browser alongside the HTML and JS, Sass variables don't exist anymore and any interpolation has already happened.
Consider swapping stylesheets based on the theme mode, or using regular CSS variables.