Avoiding Flash of Unthemed Code
If your site has a dark mode or custom theme, you might have a flash of the default theme before JavaScript loads. This site has both a light mode and a custom-settable theme, serialized into localStorage.
Previously it would load the default (dark mode) and then as the JS ran it would transition smoothly into your custom set theme. Obviously not great if you keep landing on my site and it keeps flashing you with the colors you don’t want.
I was browsing /r/reactjs and saw this post on a dark mode toggle, which led me to Donavon’s useDarkMode hook, which then led me to noflash.js.txt. Ah! Here was the solution!
Basically, inline the localStorage reading into the html you generate. I tried putting this in <svelte:head>
in my Sapper _layout.svelte
file and it worked! (It’s still WIP, because I want to add this to an auth system, but try it out!)
Here’s the code snippet for implementing custom theming in your Svelte/Sapper app!
<script>
import { onMount } from 'svelte'
import { themeStore } from '../theme.js' // a writable store
onMount(renderCSS)
themeStore.subscribe(renderCSS) // subscribe to theme updates elsewhere in the UI
function renderCSS() {
if (typeof document === 'undefined') return // SSR
const stylesheet = document.getElementById("unique-stylesheet-id");
if (!stylesheet) return // not rendered yet
let string = ``
if ($themeStore.bgColor) string += `--bg-color: ${$themeStore.bgColor};`
if ($themeStore.textColor) string += `--text-color: ${$themeStore.textColor};`
if ($themeStore.linkColor) string += `--link-color: ${$themeStore.linkColor};`
if ($themeStore.lineLength) string += `--line-length: ${$themeStore.lineLength};`
stylesheet.innerHTML = `html { ${string} }`
}
</script>
<svelte:head>
<style id="unique-stylesheet-id"> </style>
<script>
// read the stored theme if it exists,
// and add it to stylesheet, before the user sees it
(function() {
let temp = localStorage.getItem('swyx_io_themeStore')
if (temp) {
temp = JSON.parse(temp) // store object
if (typeof document === 'undefined') return // SSR
const stylesheet = document.getElementById("unique-stylesheet-id");
let string = ``
if (temp.bgColor) string += `--bg-color: ${temp.bgColor};`
if (temp.textColor) string += `--text-color: ${temp.textColor};`
if (temp.linkColor) string += `--link-color: ${temp.linkColor};`
if (temp.lineLength) string += `--line-length: ${temp.lineLength};`
stylesheet.innerHTML = `html { ${string} }`
}
})()
</script>
</svelte:head>