I have the issue commonly known as “Flash Of Unstyled Content” (FOUC) or in this specific case, “Flash Of Unthemed Content”.
A page initially loads with the default light mode style before the JavaScript responsible for applying the dark mode is executed. As a result, users experience a brief (or even not so brief!) flash of the light theme before the dark mode is applied, which can be quite annoying.
Can you, please, help with any suggestions on how to prevent this? Let me know if you need any additional information that will help to diagnose / prevent the issue. Thank you!
PS
I have attached video to my Reddit post (not sure how to post it here), but if you want to check for yourself, go to https://denshub.com/en/, switch to dark theme and just click around on various posts. You’ll see the issue.
PPS
Here is my baseof.html
file. As you can see from it, it checks for what theme is set (first script in <body>
and adds appropriate attribute to the <body>
tag like so:
<body header-desktop="fixed" header-mobile="auto" theme="dark">
But since JS with theme.min.js
loads in the very last statement {{- partial "assets.html" . -}}
, it takes some time before CSS is applied. Hence the flash.
{{- partial "init.html" . -}}
<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
<head>
<meta charset="utf-8">
<meta name="robots" content="noodp" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ block "title" . }}{{ .Site.Title }}{{ end }}</title>
{{- partial "head/gtm.html" . -}}
{{- partial "head/meta.html" . -}}
{{- partial "head/link.html" . -}}
{{- partial "head/seo.html" . -}}
{{- partial "head/adsense.html" . -}}
{{- /* Preload page when user hoovers the link */ -}}
<script src="//instant.page/5.2.0" type="module" integrity="sha384-jnZyxPjiipYXnSU0ygqeac2q7CVYMbh84q0uHVRRxEtvFPiQYbXWUorga2aqZJ0z"></script>
</head>
<body header-desktop="{{ .Site.Params.header.desktopMode }}" header-mobile="{{ .Site.Params.header.mobileMode }}">
{{- /* Check theme isDark before body rendering */ -}}
{{- $theme := .Site.Params.defaulttheme -}}
<script type="text/javascript" async>(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('{{ $theme }}' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : '{{ $theme }}' === 'dark')) && document.body.setAttribute('theme', 'dark');
</script>
{{- /* Google Tag Manager */ -}}
{{ if .Site.Params.gtm_id}}<noscript><iframe src="//www.googletagmanager.com/ns.html?id={{ .Site.Params.gtm_id }}" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>{{ end }}
<div id="back-to-top"></div>
<div id="mask"></div>
{{- /* Body wrapper */ -}}
<div class="wrapper">
{{- partial "header.html" . -}}
<main class="main">
<div class="container">
{{- block "content" . }}{{ end -}}
</div>
</main>
{{- partial "footer.html" . -}}
</div>
<div id="fixed-buttons">
{{- /* top button */ -}}
<a href="#" id="back-to-top" class="fixed-button" title="{{ T `backToTop` }}">
<i class="fas fa-arrow-up fa-fw"></i>
</a>
{{- /* comment button */ -}}
<a href="#" id="view-comments" class="fixed-button" title="{{ T `viewComments` }}">
<i class="fas fa-comment fa-fw"></i>
</a>
</div>
{{- /* Load JavaScript scripts and CSS */ -}}
{{- partial "assets.html" . -}}
</body>
</html>