fix(theme): kill flash of white on dark-themed load
Docker Build & Publish / Prune old image versions (push) Has been cancelled
Docker Build & Publish / build (push) Has been cancelled
Docker Build & Publish / push (push) Has been cancelled

The app painted white until <ThemeProvider> mounted and set data-theme,
then snapped to the dark theme. Two fixes:

- Inline head script (rsbuild html.tags) sets data-theme before first
  paint, mirroring modern-sk's exact logic (localStorage 'modern-sk-theme'
  || 'dark') so there's no second flip when the provider mounts. Inline =
  zero round-trips.
- body now paints var(--color-bg) so the themed background shows before
  React mounts #root and layers the felt grain on top.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Senko-san
2026-06-09 13:18:29 +03:00
parent dacb8b9278
commit 55aa8933af
2 changed files with 17 additions and 0 deletions
+12
View File
@@ -36,6 +36,18 @@ export default defineConfig({
// "Install app". The service worker (audio offline cache) is registered // "Install app". The service worker (audio offline cache) is registered
// from src/index.tsx, not here. // from src/index.tsx, not here.
tags: [ tags: [
// Theme bootstrap — runs inline before first paint to kill the flash of
// white on a dark-themed load. Mirrors modern-sk's own logic exactly
// (localStorage 'modern-sk-theme' || 'dark' → data-theme on <html>), so
// there's no second flip when <ThemeProvider> mounts. Inline (not an
// external file) so it costs zero round-trips.
{
tag: 'script',
children:
"(function(){try{var t=localStorage.getItem('modern-sk-theme')||'dark';document.documentElement.setAttribute('data-theme',t);}catch(e){}})();",
head: true,
append: false,
},
// Runtime operator config. A classic (non-deferred) head script, so it // Runtime operator config. A classic (non-deferred) head script, so it
// runs before the deferred app bundle and window.__APP_CONFIG__ is set by // runs before the deferred app bundle and window.__APP_CONFIG__ is set by
// the time src/config/env.ts reads it. Served from public/ in dev and // the time src/config/env.ts reads it. Served from public/ in dev and
+5
View File
@@ -28,6 +28,11 @@ body {
margin: 0; margin: 0;
font-family: var(--font-sans); font-family: var(--font-sans);
color: var(--fg-1); color: var(--fg-1);
/* Paint the themed background immediately. The inline theme script in
index.html (see rsbuild.config.ts) sets [data-theme] before first paint, so
--color-bg resolves to the right value here before React mounts #root and
layers the .modern-sk-felt grain on top — no flash of white. */
background: var(--color-bg);
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }