This note is for a general SSG. I use this method on this site (11ty).
1<span id="toggle-dark-light" href="">
2 <img src="/img_src/nav/moon.svg" alt="light-mode" height="20" width="20">
3</span>
"Cloak trick" to prevent flash load for multiple sites (because the javascripts always come behind the html/css).
💡 Idea: wait for DOM loaded + apply dark them bedhind the scene and then show the site without flashing between light/dark mode.
This script placed right after
<body>
.1<script>
2 function showTheme() {
3 // Choose the toggle icon
4 const btn = document.getElementById("toggle-dark-light");
5 let toggleIcon = btn.firstElementChild;
6 // check the saved theme on local
7 const currentTheme = localStorage.getItem("theme");
8 // switch to that saved theme (also change toggle icon)
9 if (currentTheme === "dark") {
10 document.body.classList.toggle("dark-theme");
11 toggleIcon.src = "/img_src/nav/sun.svg";
12 } else if (currentTheme === "light") {
13 document.body.classList.toggle("light-theme");
14 toggleIcon.src = "/img_src/nav/moon.svg";
15 }
16 }
17
18 // show content after DOM loaded
19 function showContent() {
20 document.body.style.visibility = 'visible';
21 document.body.style.opacity = 1;
22 }
23
24 // listen to the DOM content loaded or not?
25 window.addEventListener('DOMContentLoaded', (event) => {
26 showTheme();
27 showContent();
28 });
29</script>
Script placed before
</body>
1<script>
2 // Choose the toggle icon
3 const btn = document.getElementById("toggle-dark-light");
4 let toggleIcon = btn.firstElementChild;
5
6 // Check for dark mode preference at the OS level
7 const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
8 // Listen to click event on toggle icon
9 btn.addEventListener("click", function () {
10 // If the user's OS setting is dark and matches our .dark-theme class...
11 if (prefersDarkScheme.matches) {
12 document.body.classList.toggle("light-theme");
13 var theme = document.body.classList.contains("light-theme")
14 ? "light"
15 : "dark";
16 toggleIconFn(theme);
17 } else {
18 // Otherwise
19 document.body.classList.toggle("dark-theme");
20 var theme = document.body.classList.contains("dark-theme")
21 ? "dark"
22 : "light";
23 toggleIconFn(theme);
24 }
25 // Save the current preferred setting
26 localStorage.setItem("theme", theme);
27 });
28
29 // Change icon
30 const toggleIconFn = (theme) => {
31 if (theme === "dark") {
32 toggleIcon.src = "/img_src/nav/sun.svg";
33 } else {
34 toggleIcon.src = "/img_src/nav/moon.svg";
35 }
36 };
37</script>
If you use SCSS and wanna use custom CSS variables (
var(---var-name)
) and SCSS variable ($var-name
), please read next section.1body {
2 --text-color: #222;
3 --bkg-color: #fff;
4}
5body.dark-theme {
6 --text-color: #eee;
7 --bkg-color: #121212;
8}
9
10// Styles for users who prefer light mode at the OS level
11@media (prefers-color-scheme: dark) {
12 // defaults to light theme
13 body {
14 --text-color: #eee;
15 --bkg-color: #121212;
16 }
17 // Override dark mode with light mode styles if the user decides to swap
18 body.light-theme {
19 --text-color: #222;
20 --bkg-color: #fff;
21 }
22}
In section "For CSS", we have to write again and again the color for both dark and light mode. We can use custom variables in this case!
1// ./main.scss
2// containing the definitions of colors
3
4$text-color: #222;
5$text-color-dark: #eee;
6
7$bkg-color: #fff;
8$bkg-color-dark: #121212;
9
10@import "./mixin";
11@import "./dark-light";
1// ./_mixin.scss
2// containing the setting up for dark/light
3
4@mixin light-vars() {
5 --text-color: #{$text-color};
6 --bkg-color: #{$bkg-color};
7}
8
9@mixin dark-vars() {
10 --text-color: #{$text-color-dark};
11 --bkg-color: #{$bkg-color-dark};
12}
1// ./_dark-light.scss
2// where to apply the colors
3
4body {
5 @include light-vars();
6}
7
8body.dark-theme {
9 @include dark-vars();
10}
11
12// Styles for users who prefer light mode at the OS level
13@media (prefers-color-scheme: dark) {
14 /* defaults to light theme */
15 body {
16 @include light-vars();
17 }
18 /* Override dark mode with light mode styles if the user decides to swap */
19 body.light-theme {
20 @include dark-vars();
21 }
22}
- CSS-Tricks -- A Complete Guide to Dark Mode on the Web.