I have had support for 2 themes on my website for a long time now. I added the feature using Svelte and saved the user preference in a cookie(theme
). It was quite straightforward to implement it in Svelte.
<!-- **__layout.svelte -->**
<script>
// Default Theme - Rendered Server Side
let theme = 'light';
onMount(()=>{
const result = document.cookie.match(/theme=(.*?)(;|$)/);
// Change theme based on user's preference on the website.
theme = result && result[1] || 'theme';
});
</script>
<div class={theme}>
.... All Website Content Here ....
</div>
It worked just fine.
Then I noticed a problem with it. If the user has chosen a dark theme and then he refreshes the page, for a brief moment, light theme is visible. This flicker is a really a problem because the user has chosen dark theme and suddenly for a brief moment everything becomes white. It might cause strain in eyes in a dark setting.
The reason for this is simply because when onMount
occurs, elements are already rendered and visible on screen(with light theme) and then in onMount
theme is changed to dark
I added the following code in the app.html
itself outside the SvelteKit framework. The code has performance mark entries to measure the improvement.
performance.mark('start')
// Ensure that theme is applied before the body-wrapper is rendered on the page.
// Allowing the theme to be switched using Svelte adds a delay in theme change because statically generated pages would have light theme hardcoded and theme switches from light to dark(if required) during onMount only.
requestAnimationFrame(function ensureTheme() {
if (!document.getElementById('body-wrapper')) {
requestAnimationFrame(ensureTheme)
}
performance.mark('applyTheme');
performance.measure('themeRestoreTime', 'start');
themeToEnsure = document.cookie.match(/theme\s*=([^;]*)/);
themeToEnsure = themeToEnsure && themeToEnsure[1] || 'light';
document.getElementById('body-wrapper').classList.add(themeToEnsure);
})
I instrumented the onMount
code as well.
<!-- **__layout.svelte -->**
<script>
// Default Theme - Rendered Server Side
let theme = 'light';
onMount(()=>{
performance.mark('mountLayout')
performance.measure('svelteThemeRestoreTime', 'start', 'mountLayout');
const result = document.cookie.match(/theme=(.*?)(;|$)/);
// Change theme based on user's preference on the website.
theme = result && result[1] || 'theme';
});
</script>
<div class={theme}>
.... All Website Content Here ....
</div>
At 4x CPU, this is how it performed.
Experience during a refresh, Earlier: Notice white background
Experience during a refresh, Now : Notice there is no white background