Last active
September 12, 2019 13:39
-
-
Save nickpunt/bcd3254da3d6a848e01ea1016a91350a to your computer and use it in GitHub Desktop.
Lightswitch: A dark mode switcher with user override
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************* | |
LIGHTSWITCH: A DARK MODE SWITCHER WITH USER OVERRIDE | |
By Nick Punt 10/26/2018 | |
How to use: | |
* Create two color schemes in CSS under the classes 'light' and 'dark' | |
* Add the class 'light' or 'dark' to your body as your default color scheme | |
* Add button to page with id 'lightswitch', which lets users change/override | |
* Use the class 'flipswitch' for any style changes you want on lightswitch | |
Logic: | |
1. When user hits page for first time, color scheme is based on OS/browser | |
(if supported), otherwise it defaults to the body class you added | |
2. When user clicks lightswitch to override colors, their preference is stored | |
3. When user alters their OS light/dark mode, switch to dark if dark mode, | |
and light if light mode | |
Note: | |
The 'prefers-color-scheme' css support is currently only available in Safari | |
Technology Preview 68. | |
*******************************************************************************/ | |
// New prefers-color-scheme media query to detect OS light/dark mode setting | |
var prefers_light = window.matchMedia('(prefers-color-scheme: light)') | |
var prefers_dark = window.matchMedia('(prefers-color-scheme: dark)') | |
// Change to dark and rotate the switch icon | |
function darkmode() { | |
document.body.classList.replace('light', 'dark'); | |
document.getElementById("nav-light").classList.add("flipswitch"); | |
} | |
// Change to light and rotate the switch icon | |
function lightmode() { | |
document.body.classList.replace('dark', 'light'); | |
document.getElementById("nav-light").classList.remove("flipswitch"); | |
} | |
// Initialization triggers light/dark mode based on prior preference, then OS setting | |
if(localStorage.getItem("mode")=="dark") { | |
darkmode(); | |
} else if(localStorage.getItem("mode")=="light") { | |
lightmode(); | |
} else if(prefers_light.matches) { | |
lightmode(); | |
} else if(prefers_dark.matches) { | |
darkmode(); | |
} | |
// Fires when user clicks light/dark mode switch in top right | |
function handleThemeUpdate() { | |
if (document.body.classList.contains('light')) { | |
darkmode(); | |
localStorage.setItem("mode", "dark"); | |
} else { | |
lightmode(); | |
localStorage.setItem("mode", "light"); | |
} | |
} | |
// Runs when OS changes light/dark mode. Changes only if you were on default | |
// color state (light on light mode, dark on dark mode). | |
function OSColorChange() { | |
if (prefers_light.matches) { | |
lightmode(); | |
localStorage.setItem("mode", "light"); | |
} else if (prefers_dark.matches) { | |
darkmode(); | |
localStorage.setItem("mode", "dark"); | |
} | |
} | |
// Listeners for when you change OS setting for light/dark mode | |
prefers_light.addListener(OSColorChange) | |
prefers_dark.addListener(OSColorChange) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for the guide! This helped me a ton when setting up a dark theme on my site. I made a fork that changed setting the color themes by a class on the
<body>
to setting adata-theme
attribute on the<html>
element. In combo with making sure it's fired in the<head>
, it removes any flickering of a default theme when navigating between pages. However, because it's in the<head>
and fired before the<body>
is loaded, I think that means I can't target the#nav-light
id and change the element's classes for a switch animation.I'm new to git so sorry if I did this wrong!