Skip to content

Instantly share code, notes, and snippets.

@twhite96
Created May 9, 2022 05:51
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 twhite96/a1187bd6b3d0ab84e5b38aeb183b8cd5 to your computer and use it in GitHub Desktop.
Save twhite96/a1187bd6b3d0ab84e5b38aeb183b8cd5 to your computer and use it in GitHub Desktop.
Dark Mode Toggle
<button class="js__dark-mode-toggle dark-mode-toggle" type="button">
<span class="dark-mode-toggle__icon"></span>
<span class="dark-mode-toggle__text hidden--visually">dark mode</span>
</button>
<h1>Simple dark-mode toggle</h1>
<p>Switching dark mode with CSS custom properties and JavaScript.</p>
<p>Click the icon to switch modes.</p>
<pre><code>
&lt;button class="js__dark-mode-toggle dark-mode-toggle" type="button"&gt;
&lt;span class="dark-mode-toggle__icon"&gt; &lt;/span&gt;
&lt;span class="dark-mode-toggle__text hidden--visually"&gt;dark mode &lt;/span>
&lt;/button&gt;
</code></pre>
// Note: CodePen does not allow use of local
// storage (for sensible security reasons).
// If you're adding this code to your own site,
// reinstate the commented-out lines and the
// code will work fully.
const setDarkMode = (active = false) => {
const wrapper = document.querySelector(":root");
if (active) {
wrapper.setAttribute("data-theme", "dark");
// localStorage.setItem("theme", "dark");
} else {
wrapper.setAttribute("data-theme", "light");
// localStorage.setItem("theme", "light");
}
};
const toggleDarkMode = () => {
const theme = document.querySelector(":root").getAttribute("data-theme");
// If the current theme is "light", we want to activate dark
setDarkMode(theme === "light");
};
const initDarkMode = () => {
const query = window.matchMedia("(prefers-color-scheme: dark)");
// const themePreference = localStorage.getItem("theme");
let active = query.matches;
// if (themePreference === "dark") {
// active = true;
// }
// if (themePreference === "light") {
// active = false;
// }
setDarkMode(active);
query.addListener(e => setDarkMode(e.matches));
const toggleButton = document.querySelector(".js__dark-mode-toggle");
toggleButton.addEventListener("click", toggleDarkMode);
};
initDarkMode();
:root {
--white: #fdfdfa;
--black: #4d4d4d;
--primary: #00b7c6;
--grey--dark: #aca79a;
}
:root[data-theme="dark"] {
--white: #4d4d4d;
--black: #efeeeb;
--primary: #ff851b;
}
body {
font-size: 1rem;
color: var(--black);
background: var(--white);
font-family: monospace;
line-height: 1.7;
padding: 4rem;
}
.dark-mode-toggle {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
background: none;
display: inline-block;
border: none;
border-radius: 0;
display: flex;
align-items: center;
justify-content: center;
width: 4rem;
height: 4rem;
cursor: pointer;
overflow: hidden;
border-radius: .4rem;
border: .2rem solid var(--grey--dark);
}
.dark-mode-toggle:focus {
outline: none;
border-color: var(--primary);
}
:root[data-theme="dark"] .dark-mode-toggle__text:before {
content: "deactivate ";
}
:root[data-theme="light"] .dark-mode-toggle__text:before {
content: "activate ";
}
.dark-mode-toggle__icon {
display: block;
background: var(--grey--dark);
border-radius: 50%;
width: 2rem;
height: 2rem;
position: relative;
transition: width 0.3s, height 0.3s;
z-index: 1;
transform: rotate(-20deg);
}
.dark-mode-toggle__icon:before {
z-index: 0;
content: "";
position: absolute;
display: block;
border-right: none;
border-radius: 50%;
width: 2.4rem;
height: 2.4rem;
top: 50%;
left: 50%;
transition: opacity 0.3s, background-image 03s;
opacity: 0;
transform: translate(-50%, -50%) rotate(0deg);
animation: spin__rays 4s linear infinite;
background-image: linear-gradient(
0deg,
transparent 46%,
var(--grey--dark) 46%,
var(--grey--dark) 54%,
transparent 54%
),
linear-gradient(
90deg,
transparent 46%,
var(--grey--dark) 46%,
var(--grey--dark) 54%,
transparent 54%
),
linear-gradient(
45deg,
transparent 47%,
var(--grey--dark) 47%,
var(--grey--dark) 53%,
transparent 53%
),
linear-gradient(
135deg,
transparent 47%,
var(--grey--dark) 47%,
var(--grey--dark) 53%,
transparent 53%
);
}
.dark-mode-toggle__icon:after {
content: "";
position: absolute;
display: block;
background: var(--white);
border-radius: 0.7rem;
width: 1.4rem;
height: 1.4rem;
top: 50%;
left: 200%;
transform: translateY(-50%);
transition: left 0.3s;
}
.dark-mode-toggle:hover .dark-mode-toggle__icon {
background: var(--primary);
}
.dark-mode-toggle:hover .dark-mode-toggle__icon:before {
background-image: linear-gradient(
0deg,
transparent 47%,
var(--primary) 47%,
var(--primary) 53%,
transparent 53%
),
linear-gradient(
90deg,
transparent 47%,
var(--primary) 47%,
var(--primary) 53%,
transparent 53%
),
linear-gradient(
45deg,
transparent 48%,
var(--primary) 48%,
var(--primary) 52%,
transparent 52%
),
linear-gradient(
135deg,
transparent 48%,
var(--primary) 48%,
var(--primary) 52%,
transparent 52%
);
}
:root[data-theme="light"] .dark-mode-toggle__icon:after {
left: 40%;
}
:root[data-theme="dark"] .dark-mode-toggle__icon {
width: 1.6rem;
height: 1.6rem;
}
:root[data-theme="dark"] .dark-mode-toggle__icon:before {
opacity: 1;
}
@keyframes spin__rays {
from {
transform: translate(-50%, -50%) rotate(0deg);
}
to {
transform: translate(-50%, -50%) rotate(90deg);
}
}
/* Hide only visually, but have it available for screenreaders */
.hidden--visually {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment