How to override css prefers-color-scheme setting
Not sure, why all answers are so complicated.
Use CSS variables, set a default value, and an opposite value in a media query, as usual. Also set the values in two classes. Implement a toggle that toggles these classes when clicked.
By default, automatic light/dark mode is used based on the system color scheme. Using the toggle switches to manual light/dark mode. It returns to automatic light/dark mode after refreshing the page (or removing the class from the html element).
// toggle to switch classes between .light and .dark
// if no class is present (initial state), then assume current state based on system color scheme
// if system color scheme is not supported, then assume current state is light
function toggleDarkMode() {
if (document.documentElement.classList.contains("light")) {
document.documentElement.classList.remove("light")
document.documentElement.classList.add("dark")
} else if (document.documentElement.classList.contains("dark")) {
document.documentElement.classList.remove("dark")
document.documentElement.classList.add("light")
} else {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add("dark")
} else {
document.documentElement.classList.add("light")
}
}
}
/* automatic/manual light mode */
:root, :root.light {
--some-value: black;
--some-other-value: white;
}
/* automatic dark mode */
/* ❗️ keep the rules in sync with the manual dark mode below! */
@media (prefers-color-scheme: dark) {
:root {
--some-value: white;
--some-other-value: black;
}
}
/* manual dark mode
/* ❗️ keep the rules in sync with the automatic dark mode above! */
:root.dark {
--some-value: white;
--some-other-value: black;
}
/* use the variables */
body {
color: var(--some-value);
background-color: var(--some-other-value);
}
<button onClick="toggleDarkMode()">Toggle</button>
<h1>Hello world!</h1>
I have determined an appropriate solution, it is as follows:
CSS will use variables and themes:
// root/default variables
:root {
--font-color: #000;
--link-color:#1C75B9;
--link-white-color:#fff;
--bg-color: rgb(243,243,243);
}
//dark theme
[data-theme="dark"] {
--font-color: #c1bfbd;
--link-color:#0a86da;
--link-white-color:#c1bfbd;
--bg-color: #333;
}
The variables are then called where necessary, for example:
//the redundancy is for backwards compatibility with browsers that do not support CSS variables.
body
{
color:#000;
color:var(--font-color);
background:rgb(243,243,243);
background:var(--bg-color);
}
JavaScript is used to identify which theme the user has set, or if they have over-ridden their OS theme, as well as to toggle between the two, this is included in the header prior to the output of the html <body>...</body>
:
//determines if the user has a set theme
function detectColorScheme(){
var theme="light"; //default to light
//local storage is used to override OS theme settings
if(localStorage.getItem("theme")){
if(localStorage.getItem("theme") == "dark"){
var theme = "dark";
}
} else if(!window.matchMedia) {
//matchMedia method not supported
return false;
} else if(window.matchMedia("(prefers-color-scheme: dark)").matches) {
//OS theme setting detected as dark
var theme = "dark";
}
//dark theme preferred, set document with a `data-theme` attribute
if (theme=="dark") {
document.documentElement.setAttribute("data-theme", "dark");
}
}
detectColorScheme();
This javascript is used to toggle between the settings, it does not need to be included in the header of the page, but can be included wherever
//identify the toggle switch HTML element
const toggleSwitch = document.querySelector('#theme-switch input[type="checkbox"]');
//function that changes the theme, and sets a localStorage variable to track the theme between page loads
function switchTheme(e) {
if (e.target.checked) {
localStorage.setItem('theme', 'dark');
document.documentElement.setAttribute('data-theme', 'dark');
toggleSwitch.checked = true;
} else {
localStorage.setItem('theme', 'light');
document.documentElement.setAttribute('data-theme', 'light');
toggleSwitch.checked = false;
}
}
//listener for changing themes
toggleSwitch.addEventListener('change', switchTheme, false);
//pre-check the dark-theme checkbox if dark-theme is set
if (document.documentElement.getAttribute("data-theme") == "dark"){
toggleSwitch.checked = true;
}
finally, the HTML checkbox to toggle between themes:
<label id="theme-switch" class="theme-switch" for="checkbox_theme">
<input type="checkbox" id="checkbox_theme">
</label>
Through the use of CSS variables and JavaScript, we can automatically determine the users theme, apply it, and allow the user to over-ride it as well. [As of the current time of writing this (2019/06/10), only Firefox and Safari support the automatic theme detection]