<body>
<main>
<form onsubmit="return false;">
<button id="change-theme">Switch theme</button>
</form>
</main>
</body>
:root, .theme-white {
--base: 0, 0%;
--lightness: 100%;
--color: #1098ad;
}
.theme-dark {
--base: 210, 10%;
--lightness: 23%;
--color: white;
}
.theme-red {
--base: 0, 100%;
--lightness: 32%;
--color: white;
}
.theme-orange {
--base: 35, 100%;
--lightness: 47%;
--color: black;
}
.theme-blue {
--base: 209, 77%;
--lightness: 43%;
--color: white;
}
.theme-purple {
--base: 288, 54%;
--base2: 54%;
--lightness: 46%;
--color: #FAEAB3;
}
body {
display: flex;
justify-content: center;
height: 100vh;
align-items: center;
--bgColor: hsl(var(--base), var(--lightness));
--darkerBg: hsl(var(--base), calc(var(--lightness) - 10%));
background-color: var(--bgColor);
color: var(--color);
}
button {
height: 3em;
font-size: 1.3rem;
color: inherit;
background-color: var(--darkerBg);
border: none;
cursor: pointer;
}
const CURRENT_THEME_KEY = "current_theme_idx"
// Look if there is a theme already set
const currentTheme = localStorage.getItem(CURRENT_THEME_KEY)
const themeToggle = document.getElementById("change-theme")
function getAvailableThemes() {
// Ideally use something like:
// const mainStylesheet = Array.from(document.styleSheets).find(
// s => s.title === "main"
// )
const mainStylesheet = Array.from(document.styleSheets)[0]
const rules = Array.from(mainStylesheet.rules)
// All themes are class selectors that start with "theme-"
return rules
.filter(
r =>
Boolean(r.selectorText) &&
r.selectorText.includes("theme-")
)
// get name without dot prefix on a capture group
.map(r => r.selectorText.match(/\.([^\s]*)/)[1])
}
const themes = getAvailableThemes()
const mediaQuery = matchMedia("(prefers-color-scheme: dark)")
let defaultTheme = mediaQuery.matches ? "theme-dark" : "theme-white"
mediaQuery.addEventListener("change", val => {
defaultTheme = mediaQuery.matches ? "theme-dark" : "theme-white"
setTheme()
})
function setTheme(idx = null) {
if(idx !== null) {
document.body.className = themes[idx]
// store idx of selected theme
localStorage.setItem("current_theme_idx", idx)
} else if (currentTheme) {
document.body.className = themes[currentTheme]
} else {
document.body.className = defaultTheme
}
}
themeToggle.addEventListener("click", function toggleTheme() {
const currentTheme = Array.from(document.body.classList).find(val => themes.includes(val)) ||
defaultTheme
const idx = themes.indexOf(currentTheme)
const nextIdx = (idx + 1) % themes.length
setTheme(nextIdx)
})
setTheme()
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.