-
Notifications
You must be signed in to change notification settings - Fork 1.5k
fix: resolve dark mode white flash on initial page load #7446
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
65 commits
Select commit
Hold shift + click to select a range
0a904a2
fix: resolve dark mode white flash on initial page load
AnkitRewar11 e4034dd
fix: add fallback background color to prevent white flash
AnkitRewar11 16be0d1
fix: correct setHtmlAttributes style format
AnkitRewar11 4c00b0f
fix: use correct dark theme color and inject head styles to prevent w…
AnkitRewar11 e238605
fix: set isDark default to true to prevent white flash on SSR
AnkitRewar11 852ec25
fix: dynamically apply correct SSR background to prevent theme flash
AnkitRewar11 dc10791
fix: revert isDark default to false to prevent dark flash
AnkitRewar11 cdd8e7d
fix: prevent FOUC using head CSS and class injection
AnkitRewar11 8fd5caa
Refactor theme handling in onRenderBody.js
AnkitRewar11 5f76bbf
Fix export statement for wrapPageElement
AnkitRewar11 9c62040
Add setPreBodyComponents to onRenderBody function
AnkitRewar11 9095d71
Change background color for dark mode and light mode
AnkitRewar11 3116aa9
Refactor theme management in onRenderBody.js
AnkitRewar11 322087f
Fix export statement for wrapPageElement
AnkitRewar11 2a16756
Improve comments and add dark theme styles
AnkitRewar11 5e7754e
Update theme handling in onRenderBody.js
AnkitRewar11 c91e7ac
Simplify theme detection and background color setting
AnkitRewar11 63cb585
Set default theme to dark mode
AnkitRewar11 b4d50da
fix: set dark mode as default to prevent white flash on initial load
AnkitRewar11 317d48d
Clean up comments in onRenderBody.js
AnkitRewar11 0aca758
Refactor StyledThemeProvider by cleaning up comments
AnkitRewar11 0626e11
Update onRenderBody.js
AnkitRewar11 5b275bf
Update ThemeManager.js
AnkitRewar11 a56ebe2
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 f3c5dcf
Update onRenderBody.js
AnkitRewar11 daea70b
Update onRenderBody.js
AnkitRewar11 c839a55
Update onRenderBody.js
AnkitRewar11 03365ec
Update onRenderBody.js
AnkitRewar11 624c764
Update onRenderBody.js
AnkitRewar11 7daec77
Update onRenderBody.js
AnkitRewar11 017f1db
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 cf3513f
Update onRenderBody.js
AnkitRewar11 31498d4
Update ThemeManager.js
AnkitRewar11 1a4d141
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 da0f2b8
Update onRenderBody.js
AnkitRewar11 23e099a
Update onRenderBody.js
AnkitRewar11 9b69325
Update onRenderBody.js
AnkitRewar11 540703d
Update onRenderBody.js
AnkitRewar11 5379bf5
Update onRenderBody.js
AnkitRewar11 b28a75c
Update onRenderBody.js
AnkitRewar11 1b5251e
Update ThemeManager.js
AnkitRewar11 b7782ab
Update StyledThemeProvider.js
AnkitRewar11 b87fa6f
Update ThemeManager.js
AnkitRewar11 a047e3e
Update StyledThemeProvider.js
AnkitRewar11 66946e4
Update onRenderBody.js
AnkitRewar11 c2554d1
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 56c3d1c
Update fonts.css
AnkitRewar11 1b78744
Update onRenderBody.js
AnkitRewar11 165cfdd
Update onRenderBody.js
AnkitRewar11 2c527e1
Update onRenderBody.js
AnkitRewar11 924ab63
Update fonts.css
AnkitRewar11 2cbe036
Update onRenderBody.js
AnkitRewar11 68cebea
Update onRenderBody.js
AnkitRewar11 c3b41ee
Update fonts.css
AnkitRewar11 982b5cc
Update onRenderBody.js
AnkitRewar11 f9967fd
Update fonts.css
AnkitRewar11 0eac38e
Update onRenderBody.js
AnkitRewar11 f2e4925
Update fonts.css
AnkitRewar11 3d55b3d
Update onRenderBody.js
AnkitRewar11 abbe4ec
Update onRenderBody.js
AnkitRewar11 91a4d78
Update onRenderBody.js
AnkitRewar11 7a6af92
Update StyledThemeProvider.js
AnkitRewar11 ad4ffff
Update ThemeManager.js
AnkitRewar11 9464fb8
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 7439582
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,57 +1,70 @@ | ||
| import React from "react"; | ||
| import { DarkThemeKey, ThemeSetting } from "./src/theme/app/ThemeManager.js"; | ||
| import { DarkThemeKey, ThemeSetting } from "./src/theme/app/ThemeManager"; | ||
| import lighttheme, { darktheme } from "./src/theme/app/themeStyles"; | ||
|
|
||
| const themes = { light: lighttheme, dark: darktheme }; | ||
| const themes = { | ||
| light: lighttheme, | ||
| dark: darktheme, | ||
| }; | ||
|
|
||
| const MagicScriptTag = ({ theme }) => { | ||
| const themeJSON = JSON.stringify(theme); | ||
|
|
||
| const MagicScriptTag = (props) => { | ||
| const codeToRunOnClient = ` | ||
| (function() { | ||
| // 1. Keeps SYSTEM as the priority preference | ||
| const themeFromLocalStorage = localStorage.getItem('${DarkThemeKey}') || '${ThemeSetting.SYSTEM}'; | ||
|
|
||
| // 2. We change the check to look for LIGHT mode explicitly | ||
| const systemLightModeSetting = () => window.matchMedia ? window.matchMedia('(prefers-color-scheme: light)') : null; | ||
|
|
||
| const isLightModeActive = () => { | ||
| return !!systemLightModeSetting()?.matches; | ||
| }; | ||
|
|
||
| let colorMode; | ||
| switch (themeFromLocalStorage) { | ||
| case '${ThemeSetting.SYSTEM}': | ||
| // LOGIC CHANGE: If Light is active -> Light. Otherwise (Dark, No Preference, or Error) -> Dark. | ||
| colorMode = isLightModeActive() ? '${ThemeSetting.LIGHT}' : '${ThemeSetting.DARK}' | ||
| break | ||
| case '${ThemeSetting.DARK}': | ||
| case '${ThemeSetting.LIGHT}': | ||
| colorMode = themeFromLocalStorage | ||
| break | ||
| default: | ||
| // 3. Fallback to DARK in case of error | ||
| colorMode = '${ThemeSetting.DARK}' | ||
| } | ||
|
|
||
| const root = document.documentElement; | ||
| const iterate = (obj) => { | ||
| if (!obj) return; | ||
| Object.keys(obj).forEach(key => { | ||
| if (typeof obj[key] === 'object') { | ||
| iterate(obj[key]) | ||
| } else { | ||
| root.style.setProperty("--" + key, obj[key]) | ||
| } | ||
| }) | ||
| } | ||
| const parsedTheme = JSON.parse('${JSON.stringify(props.theme)}') | ||
| const theme = parsedTheme[colorMode] | ||
| iterate(theme) | ||
| root.style.setProperty('--initial-color-mode', colorMode); | ||
| })() | ||
| `; | ||
| (function() { | ||
| try { | ||
| var themeFromLocalStorage = localStorage.getItem('${DarkThemeKey}') || '${ThemeSetting.SYSTEM}'; | ||
| var systemLightModeSetting = function() { | ||
| return window.matchMedia ? window.matchMedia('(prefers-color-scheme: light)') : null; | ||
| }; | ||
| var isLightModeActive = function() { | ||
| var mql = systemLightModeSetting(); | ||
| return mql ? mql.matches : false; | ||
| }; | ||
|
|
||
| var colorMode; | ||
| switch (themeFromLocalStorage) { | ||
| case '${ThemeSetting.SYSTEM}': | ||
| colorMode = isLightModeActive() ? '${ThemeSetting.LIGHT}' : '${ThemeSetting.DARK}'; | ||
| break; | ||
| case '${ThemeSetting.DARK}': | ||
| case '${ThemeSetting.LIGHT}': | ||
| colorMode = themeFromLocalStorage; | ||
| break; | ||
| default: | ||
| colorMode = '${ThemeSetting.DARK}'; | ||
| } | ||
|
|
||
| var root = document.documentElement; | ||
| var parsedTheme = ${themeJSON}; | ||
| var selectedTheme = parsedTheme[colorMode]; | ||
|
|
||
| var iterate = function(obj) { | ||
| if (!obj) return; | ||
| Object.keys(obj).forEach(function(key) { | ||
| if (typeof obj[key] === 'object' && obj[key] !== null) { | ||
| iterate(obj[key]); | ||
| } else { | ||
| root.style.setProperty('--' + key, obj[key]); | ||
| } | ||
| }); | ||
| }; | ||
|
|
||
| iterate(selectedTheme); | ||
| root.style.setProperty('--initial-color-mode', colorMode); | ||
| root.setAttribute('data-theme', colorMode); | ||
|
|
||
| window.__theme = colorMode; | ||
|
|
||
| } catch (e) {} | ||
| })(); | ||
| `; | ||
|
|
||
| return <script dangerouslySetInnerHTML={{ __html: codeToRunOnClient }} />; | ||
| }; | ||
|
|
||
| export const onRenderBody = ( { setPreBodyComponents }) => { | ||
| setPreBodyComponents(<MagicScriptTag key="theme-injection" theme={themes} />); | ||
| export const onRenderBody = ({ setHeadComponents }) => { | ||
| setHeadComponents([ | ||
| <MagicScriptTag key="theme-initializer" theme={themes} />, | ||
| ]); | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AnkitRewar11 Any reason, why you removed this ? I think we cannot delete this CSS variable injection loop. Layer5's styled components rely on these --primary, --text, etc. variables being present in the HTML before React fully loads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @YASHMAHAKAL! Thanks for pointing these out.
if (!didLoad) return nullI added this to prevent the white flash before the theme loads. My idea was to block rendering until the correct theme is available. I didn’t realize it would break Gatsby SSR and result in empty HTML. I’ll revert this.CSS variable injection loop I removed it thinking that the
data-themeattribute and thebackgroundColorinline style would be enough to prevent FOUC. But you’re right, styled components depend on those CSS variables being present before React hydrates, so I’ll restore it.Also, apart from these changes, am I moving in the right direction?