Flash Of Unstyled Content

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.

:point_right: 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>

I’d recommend applying theme on <html> and moving theme setting JS to <head>, so it can make sure the <body> is using the right theme before being rendering, one example of my theme: https://images.hugomods.com/.

You might need to tweak your style a little bit with this approach.

Very interesting idea, @razon! Thank you very much for it, I will definitely try!
By the way, thanks for sharing link to your site, interesting modules, will learn them too.

And as a side note, when on this page: HugoMods | Hugo Modules and Tools I click ‘Learn more ->’ your site first takes me to this address: Hugo Images Module - Docs - HugoMods, which quickly reloads to this URL: https://images.hugomods.com/ Just for your information.