If you change styles on the <body>
you get FOUC (Flash Of Unstyled Content). Try using a close equivalent like <main>
and spread it 100% x 100% and <html>
and <body>
as well, but give them margin
and padding
of 0 in order to ensure <main>
covers them completely.
The [disabled]
attribute for the <link>
is the best way of toggling them because they are still loaded but inert. Also, in the example there is a function called loadTheme(e)
that is loaded on the 'DOMContentLoaded'
event which insures that all of the DOM is loaded before hand. The example below will not work because localStorage
is blocked on SO. There is a functioning example on Plunker. To test it:
- Click the green Preview button.
- Another frame should appear on the right. Within the frame is the webpage example click the ☀️ button.
- It should be in dark mode now. Next, click the refresh ⟳ button located in the mini-toolbar within the frame or press ctrl+enter for Windows OS or ⌥+return for Mac OS.
- The page should still be in dark mode. 👍
/* night.css
main {
background: #000;
color: #fff;
}
*/
/* default.css */
:root {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
font: 1ch/1.5 'Segoe UI';
}
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
font-size: 4ch;
}
main {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
color: #000;
}
form {
width: 80vw;
margin: 20px auto;
}
fieldset {
width: max-content;
min-height: 25px;
margin-left: auto;
padding: 0 1.5px 1.5px;
border-radius: 8px;
background: inherit;
color: inherit;
}
button {
display: block;
width: 100%;
height: 100%;
border: 0;
font-size: 4rem;
text-align: center;
background: transparent;
cursor: pointer;
}
#theme::before {
content: '☀️';
}
.night #theme::before {
content: '🌙';
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://stackoverflow.com/questions/71031101/lib/default.css" rel="stylesheet">
<link class="night" href="lib/night.css" rel="stylesheet" disabled>
<style></style>
</head>
<body>
<main>
<form id='UI'>
<fieldset name="box">
<legend>Theme</legend>
<button id='theme' type="button"></button>
</fieldset>
<p>Click the "Theme" switch to toggle between `disabled` `true` and `false` on `night.css` and `light.css` `
<link>`s.</p>
</form>
</main>
<script>
const UI = document.forms.UI;
const M = document.querySelector('main');
const L = document.querySelector('.night')
const switchTheme = e => {
const clk = e.target;
if (clk.matches('button')) {
M.classList.toggle('night');
L.toggleAttribute('disabled');
}
let status = M.className === 'night' ? 'on' : 'off';
localStorage.setItem('theme', status);
};
const loadTheme = e => {
let cfg = localStorage.getItem('theme');
if (cfg === 'on') {
M.classList.add('night');
L.removeAttribute('disabled');
} else {
M.classList.remove('night');
L.setAttribute('disabled', true);
}
};
UI.addEventListener('click', switchTheme);
document.addEventListener('DOMContentLoaded', loadTheme);
</script>
</body>
</html>