So I have a bit of script for toggling between light and dark modes on my site. The dark mode is the default. Problem is, whenever the light mode is toggled on, with every page load it flickers to the dark mode for just a second before loading the light mode. I would really like it to not do this and super appreciate any help you all can give. Thanks in advance!
My Code is as follows:
if (localStorage['blackout']) {
if (Number(localStorage['blackout']) == 1) {
$('BODY').addClass('blackout');
} else {
$('BODY').removeClass('blackout');
}
} else {
localStorage['blackout'] = 0;
$('BODY').removeClass('blackout');
}
$('BODY').show();
$('#boToggle').on('click', function(){
if (Number(localStorage['blackout']) == 0) {
localStorage['blackout'] = 1;
$('BODY').addClass('blackout');
} else {
localStorage['blackout'] = 0;
$('BODY').removeClass('blackout');
}
});
So I have a bit of script for toggling between light and dark modes on my site. The dark mode is the default. Problem is, whenever the light mode is toggled on, with every page load it flickers to the dark mode for just a second before loading the light mode. I would really like it to not do this and super appreciate any help you all can give. Thanks in advance!
My Code is as follows:
if (localStorage['blackout']) {
if (Number(localStorage['blackout']) == 1) {
$('BODY').addClass('blackout');
} else {
$('BODY').removeClass('blackout');
}
} else {
localStorage['blackout'] = 0;
$('BODY').removeClass('blackout');
}
$('BODY').show();
$('#boToggle').on('click', function(){
if (Number(localStorage['blackout']) == 0) {
localStorage['blackout'] = 1;
$('BODY').addClass('blackout');
} else {
localStorage['blackout'] = 0;
$('BODY').removeClass('blackout');
}
});
Share
Improve this question
asked Jun 29, 2020 at 9:39
Charmaine SimpsonCharmaine Simpson
411 silver badge2 bronze badges
0
2 Answers
Reset to default 5Put your JS (the part reading from local storage and applying the class) in the <head>
section, and add the class to the <html>
tag, so that it get executed before the body
is parsed and displayed.
You can try it with this simple working demo:
<html>
<head>
<script>
// Do this before the body gets parsed
if (localStorage.getItem('darkmode') === '1') {
document.documentElement.classList.add('darkmode');
}
</script>
<style>
.darkmode body { background: #222; }
.darkmode .light-only { display: none; }
html:not(.darkmode) .dark-only { display: none; }
</style>
</head>
<body>
<button id="darkToggle">
Switch to
<span class="dark-only">light</span>
<span class="light-only">dark</span>
mode
</button>
<script>
document.querySelector('#darkToggle').addEventListener('click', function() {
var wasDarkMode = localStorage.getItem('darkmode') === '1';
localStorage.setItem('darkmode', wasDarkMode ? '0' : '1');
document.documentElement.classList[wasDarkMode ? 'remove' : 'add']('darkmode');
});
</script>
</body>
</html>
In case anyone else is having this issue and this helps; my solution to this was to store the chosen theme in the user's session data, and then ensuring the correct class was applied when in the HTML.
Here is my JavaScript client code:
window.getTheme = function () {
let theme = localStorage.getItem('theme');
if (!["dark", "light"].includes(theme)) {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
return theme;
}
window.setTheme = function (theme) {
if (theme) {
localStorage.setItem('theme', theme);
// You could use the fetch API here instead...
axios.post('/theme', { theme });
} else {
theme = getTheme();
}
document.querySelector('body').classList.remove('dark', 'light');
document.querySelector('body').classList.add(theme);
}
window.unsetTheme = function () {
localStorage.removeItem('theme');
setTheme();
}
window.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', e => {
setTheme();
});
setTheme();
I'm using Laravel in the back end, so here's a simple handler for the theme endpoint:
Route::post('theme', function () {
$theme = request('theme');
if (in_array($theme, ['light', 'dark'])) {
Session::put('theme', $theme);
}
})->name('theme');
Finally we then need to add this to the body in the main layout:
<body class="font-sans antialiased {{Session::get("theme")}}">