如何修复Next.js 13中暗黑主题闪烁问题
主题切换闪烁问题:Next.js站点初始加载先显示浅色再切深色
我有一个基于Next.js、Typescript、MUI、TinaCMS和Redux的站点,支持深色与浅色主题,主题状态存储在localStorage中并通过Redux管理,默认主题为深色。目前遇到的问题是:进入页面时会先显示约0.5秒的浅色主题,之后才切换为深色主题。
我已配置自定义文档/pages/_document.tsx,在其中引入了/scripts/theme.js脚本和ThemeProvider,相关代码如下:
theme.js 代码
// Code duplicate to prevent the following error: // https://github.com/vercel/next.js/discussions/12533 (() => { const defaultTheme = "dark"; const getStorageTheme = () => { return localStorage.theme; }; const getBrowserTheme = () => { if (window.matchMedia === undefined) { return undefined; } if (window.matchMedia("(prefers-color-scheme: light)").matches) { return "light"; } else { return "dark"; } }; const getInitialTheme = () => getStorageTheme() || getBrowserTheme() || defaultTheme; const theme = getInitialTheme(); localStorage.setItem("theme", theme); const body = document.querySelector("body"); if (theme === "dark") { body?.classList.add("dark-theme"); } else { body?.classList.remove("dark-theme"); } })();
_document.tsx 代码
/* eslint-disable @next/next/no-sync-scripts */ import { Head, Html, Main, NextScript } from "next/document"; import Script from "next/script"; const Document = () => ( <Html lang="en"> <Head> <Script src="/scripts/theme.js" strategy="beforeInteractive" /> </Head> <body> <Main /> <NextScript /> </body> </Html> ); export default Document;
/components/MUI/ThemeProvider.tsx 代码
import { PaletteMode, ThemeProvider as MUIThemeProvider } from "@mui/material"; import { defaultTheme, setTheme, Theme } from "redux/slices/theme"; import { useAppDispatch, useAppSelector } from "redux/typesHooks"; import useIsomorphicLayoutEffect from "../useIsomorphicLayoutEffect"; import getMUITheme from "./getMUITheme"; interface Props { children: JSX.Element; } const getStorageTheme = (): Theme | undefined => { return localStorage.theme; }; const getBrowserTheme = (): Theme | undefined => { if (window.matchMedia === undefined) { return undefined; } if (window.matchMedia("(prefers-color-scheme: light)").matches) { return "light"; } else { return "dark"; } }; const getInitialTheme = (): Theme => getStorageTheme() || getBrowserTheme() || defaultTheme; const ThemeProvider = ({ children }: Props) => { const dispatch = useAppDispatch(); const theme = useAppSelector((state) => state.theme); const MUITheme = getMUITheme(theme as PaletteMode); useIsomorphicLayoutEffect(() => { const initialTheme = getInitialTheme(); dispatch(setTheme(initialTheme)); }, [dispatch]); return <MUIThemeProvider theme={MUITheme}>{children}</MUIThemeProvider>; }; export default ThemeProvider;
我曾尝试过相关方案,但完全没有效果。
内容的提问来源于stack exchange,提问作者Winheart
相关产品推荐
相关产品推荐

