theme-toggle-switch

Файли-джерела
- index.html
header.header.sticky-active
Бібліотеки
jquery
Summary
A floating pill toggle (#theme-toogle) anchored bottom-right, that flips the document data-theme attribute between dark and light. Choice is persisted in localStorage; first paint respects prefers-color-scheme. Light-mode styling is a single _light-mode.scss override sheet keyed off [data-theme="light"], so no class swapping is required at runtime.
HTML structure (minimal)
<div id="theme-toogle" class="switcher-button">
<div class="switcher-button-inner-left"></div>
<div class="switcher-button-inner"></div>
</div>
Key SCSS tokens
#theme-toogle {
position: fixed; bottom: 30px; left: 30px;
width: 60px; height: 30px; border-radius: 999px;
background: var(--rr-color-bg-1);
border: 1px solid var(--rr-color-border-1);
cursor: pointer; z-index: 990;
display: flex; align-items: center; justify-content: space-between;
padding: 0 4px;
.switcher-button-inner,
.switcher-button-inner-left {
width: 22px; height: 22px; border-radius: 50%;
background: var(--rr-color-theme-primary);
transition: transform .3s ease;
}
}
[data-theme="light"] #theme-toogle .switcher-button-inner {
transform: translateX(-30px);
}
Animation logic
const storageKey = 'theme-preference';
const getColorPreference = () => {
if (localStorage.getItem(storageKey)) return localStorage.getItem(storageKey);
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
};
const reflectPreference = () => {
document.firstElementChild.setAttribute('data-theme', theme.value);
document.querySelector('#theme-toogle')?.setAttribute('aria-label', theme.value);
};
const setPreference = () => {
localStorage.setItem(storageKey, theme.value);
reflectPreference();
};
const onClick = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light';
setPreference();
};
const theme = { value: getColorPreference() };
reflectPreference(); // run before window load → no FOUC
$(window).on("load", function () {
reflectPreference();
document.querySelector('#theme-toogle').addEventListener('click', onClick);
});
Notable details
reflectPreference()is called BEFORE$(window).on("load", …)so thedata-themeattribute is on<html>before any CSS paints — eliminates the first-paint flash typical of theme toggles.- The pattern uses
data-themeattribute selectors instead of class swapping — every light-mode rule lives in_light-mode.scssas[data-theme="light"] selector { … }. Cleaner than.theme-lightcascade overrides. - All visual assets that have light/dark variants (icons, logos) ship as paired
<img class="dark-img">+<img class="light-img">; the light-mode CSS hides one and reveals the other — no JS image swap.
Use when
- Templates that ship both palettes and want a no-flicker theme switcher without React.
- Content sites where users may have a
prefers-color-schemepreference but the in-app toggle should override it.
Caveats
- The element id
#theme-toogleis misspelled in the source ("toogle" instead of "toggle"). Fix carefully — it's referenced from both HTML and JS. - localStorage is read on every page load even before the DOM is ready, so SSR'd implementations may see a brief mismatch; fine for static HTML templates.
- No system-change listener — if the user toggles their OS theme mid-session the page won't follow until the next reload.