A Pen by Tom Hazledine on CodePen.
Created
May 9, 2022 05:51
-
-
Save twhite96/a1187bd6b3d0ab84e5b38aeb183b8cd5 to your computer and use it in GitHub Desktop.
Dark Mode Toggle
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
<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> | |
<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> | |
</code></pre> |
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
// 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(); |
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
: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