fix: theme flash

This commit is contained in:
Cory Dransfeldt 2024-02-17 20:02:25 -08:00
parent cf99fba91c
commit 422ac5fb79
No known key found for this signature in database
5 changed files with 78 additions and 38 deletions

View file

@ -36,33 +36,51 @@ The `client-side` class above hides the button should the user have JavaScript d
</noscript>
```
And JavaScript is used to control the behavior of the toggle:
And JavaScript is used to control the behavior of the toggle — first, in the `<body>` of my base template:
{% raw %}
```liquid
{% capture js %}
{% render "../assets/scripts/theme.js" %}
{% endcapture %}
<script>{{ js }}</script>
```
{% endraw %}
Where `theme.js` sets the initial state:
```javascript
;(async function() {
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)').matches;
const currentTheme = localStorage?.getItem('theme');
if (currentTheme === 'dark') {
document.body.classList.add('theme__dark');
} else if (currentTheme === 'light') {
document.body.classList.add('theme__light');
} else if (prefersDarkScheme) {
document.body.classList.add('theme__dark');
} else if (!prefersDarkScheme) {
document.body.classList.add('theme__light');
}
})()
```
With the following JavaScript set in `assets/scripts/index.js` to add the `click` event listener for the theme toggle:
```javascript
;(async function() {
const btn = document.querySelector('.theme__toggle');
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)').matches; // check the user's OS appearance preference
const currentTheme = localStorage?.getItem('theme'); // check if a theme has been set
let theme;
if (!currentTheme) localStorage?.setItem('theme', (prefersDarkScheme ? 'dark' : 'light')) // if a theme hasn't been set, set one based on their OS preference
// set the body class based on the derived preferences above
if (currentTheme === 'dark') {
document.body.classList.toggle('theme__dark');
} else if (currentTheme === 'light') {
document.body.classList.toggle('theme__light');
} else if (prefersDarkScheme) {
document.body.classList.toggle('theme__dark');
} else if (!prefersDarkScheme) {
document.body.classList.toggle('theme__light');
}
// allow the user to toggle the theme by clicking the theme button
btn.addEventListener('click', () => {
document.body.classList.toggle('theme__light');
document.body.classList.toggle('theme__dark');
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)').matches;
const currentTheme = localStorage?.getItem('theme');
let theme;
if (!currentTheme) localStorage?.setItem('theme', (prefersDarkScheme ? 'dark' : 'light'))
if (prefersDarkScheme) {
theme = document.body.classList.contains('theme__light') ? 'light' : 'dark';
} else {
@ -138,4 +156,6 @@ Finally, the theme is updated based on the body class applied by the JavaScript,
}
```
With those changes in place, visitors can toggle whichever theme they'd prefer and their preference is persisted in `localStorage` should it be available.
With those changes in place, visitors can toggle whichever theme they'd prefer and their preference is persisted in `localStorage` should it be available.
**EDIT:** Many thanks to [Tixie Salander](https://mastodon.guerilla.studio/@tixie) for [guiding me to a solution that improves the initial load experience](https://mastodon.guerilla.studio/@tixie/111950371813634672).