I've been developing a static website using NuxtJS where users can choose between dark mode and default CSS media query selectors. Here is the code snippet for achieving this:
<template>
<div class="container">
<vertical-nav />
<!-- content wrapper with conditional class binding based on colorScheme state -->
<div id="content-wrapper" :class="colorScheme !== null ? colorScheme : ''">
<nuxt />
</div>
</div>
</template>
<script>
import { mapMutations, mapState } from 'vuex';
import VerticalNav from '@/components/VerticalNav.vue';
export default {
components: {
VerticalNav,
},
computed: mapState(['colorScheme']), // Vuex state to store user preference
mounted() {
this.getPreferredColorScheme(); // Vuex mutation to set initial state
},
methods: mapMutations(['getPreferredColorScheme']),
};
Upon initial page load, I observed a flickering effect as seen in this screen recording, especially when browser cache is disabled.
Further investigation reveals that this issue occurs only on the first visit, not on subsequent reloads. It seems to be connected to font loading and subsequent reflows indicated by this water fall. Notably, the use of display=swap
is avoided here. Additionally, Chrome profiler data shows style recalculation and layout changes during the flicker (time range 4.26s to 4.32s).
Could the flash of invisible text be due to how I'm applying the optional class through binding? If class binding isn't the root cause, what could be causing this issue and how can it be resolved?
UPDATE: After thorough analysis, this behavior appears unique to Chrome and may relate to self-hosted fonts used. Firefox and Safari do not exhibit this repaint issue.