Skip to content

Instantly share code, notes, and snippets.

@pborenstein
Created July 27, 2020 03:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pborenstein/30d9a226cd84aa9ba7366295b2ef33a2 to your computer and use it in GitHub Desktop.
Save pborenstein/30d9a226cd84aa9ba7366295b2ef33a2 to your computer and use it in GitHub Desktop.
minimal — User controlled dark mode
<main>
<article>
<h1>Dark mode should be a user preference—not presumed</h1>
<p>Yes, by default, when a user has <code>@media (prefers-color-scheme: dark)</code> set, we should set a dark theme, but we should also provide a switch for if the dark them isn’t working out for them.</p>
<p>This also benefits users that don’t have <code>@media (prefers-color-scheme: dark)</code> set because they get a toggle to choose, too.</p>
</article>
<div class="user-toggle">
<button class="toggle">
toggle
</button>
<button class="reset">reset</button>
</div>
</main>
const STORAGE_KEY = 'user-color-scheme';
const COLOR_MODE_KEY = '--color-mode';
const toggleButton = document.querySelector('.toggle');
const resetButton = document.querySelector('.reset');
const getCSSCustomProp = (propKey) => {
let response = getComputedStyle(document.documentElement).getPropertyValue(propKey);
if (response.length) {
response = response.replace(/\'|"/g, '').trim();
}
return response;
};
/**
* Takes either a passed settings ('light'|'dark') or grabs that from localStorage.
* If it can’t find the setting in either, it tries to load the CSS color mode,
* controlled by the media query
*/
const applySetting = passedSetting => {
let currentSetting = passedSetting || localStorage.getItem(STORAGE_KEY);
if(currentSetting) {
document.documentElement.setAttribute('data-user-color-scheme', currentSetting);
}
}
/**
* Gets the current setting > reverses it > stores it
*/
const toggleSetting = () => {
let currentSetting = localStorage.getItem(STORAGE_KEY);
switch(currentSetting) {
case null:
currentSetting = getCSSCustomProp(COLOR_MODE_KEY) === 'dark' ? 'light' : 'dark';
break;
case 'light':
currentSetting = 'dark';
break;
case 'dark':
currentSetting = 'light';
break;
}
localStorage.setItem(STORAGE_KEY, currentSetting);
return currentSetting;
}
toggleButton.addEventListener('click', evt => {
applySetting(toggleSetting());
});
resetButton.addEventListener('click', evt => {
localStorage.clear()
document.documentElement.removeAttribute('data-user-color-scheme');
});
applySetting();
:root {
--color-mode: 'light';
--color-dark: #141414;
--color-dark-alpha: rgba(0, 0, 0, 0.1);
--color-light: #efefef;
--color-light-alpha: rgba(255, 255, 255, 0.9);
}
:root {
--background: var(--color-light);
--text-color: var(--color-dark);
--border-color: var(--color-dark-alpha);
}
:root {
--color-mode: 'light';
}
@media (prefers-color-scheme: dark) {
:root {
--color-mode: 'dark';
}
:root:not([data-user-color-scheme]) {
--background: var(--color-dark);
--text-color: var(--color-light);
--border-color: var(--color-light-alpha);
}
}
[data-user-color-scheme="dark"] {
--background: var(--color-dark);
--text-color: var(--color-light);
--border-color: var(--color-light-alpha);
}
body {
background: var(--background);
color: var(--text-color);
transition: background 500ms ease-in-out, color 200ms ease;
}
/* Presentational demo styles */
body {
font-family: sans-serif;
padding: 2rem 1rem;
line-height: 1.4;
display: grid;
place-items: center;
}
article {
max-width: 75ch;
margin: 0 auto;
}
article > * + * {
margin-top: 1em;
}
h1 {
font-size: 2.5rem;
line-height: 1.1;
}
p {
font-size: 1.2rem;
opacity: 0.9;
}
code {
font-weight: 700;
font-size: 1.3em;
white-space: pre;
}
<link href="https://codepen.io/andybelldesign/pen/Ygmwym.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment