You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SSR模式下暗黑模式初始渲染闪烁及data-theme设置咨询

在Next.js SSR中解决暗黑模式首次加载不生效的问题

核心问题是SSR阶段无法直接访问浏览器的localStorage或window对象,导致首次渲染的根元素(<html>)没有带上data-theme属性。要解决这个问题,需要通过Cookie传递用户主题偏好,让服务端在渲染时就能注入正确的属性。

步骤1:在客户端存储主题偏好并同步到Cookie

用户切换主题时,除了更新localStorage和根元素的data-theme,还要把主题值写入Cookie,这样服务端能读取到:

const toggleTheme = () => {
  const currentTheme = document.documentElement.dataset.theme;
  const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
  
  // 更新根元素属性
  document.documentElement.dataset.theme = newTheme;
  // 存储到localStorage
  localStorage.setItem('theme', newTheme);
  // 写入Cookie,设置长期有效期
  document.cookie = `theme=${newTheme}; path=/; max-age=31536000`;
};

步骤2:在_document.tsx中从Cookie读取主题并注入根元素

_document.tsx是Next.js的SSR入口文件,在这里可以通过请求对象读取Cookie,然后给<html>标签设置data-theme:

import Document, { Html, Head, Main, NextScript } from 'next/document';

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    
    // 解析请求头中的Cookie,提取主题值
    const themeCookie = ctx.req?.headers.cookie?.split('; ')
      ?.find(row => row.startsWith('theme='))
      ?.split('=')[1];
    
    // 优先级:Cookie存储的主题 > 系统主题偏好(仅客户端)> 默认light
    const userTheme = themeCookie || (
      typeof window !== 'undefined' 
        ? window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
        : 'light'
    );

    return { ...initialProps, userTheme };
  }

  render() {
    return (
      <Html data-theme={this.props.userTheme}>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

步骤3:在_app.tsx中同步客户端状态(可选但保险)

为了避免客户端和服务端状态不一致,在_app.tsx中再做一次同步,确保客户端渲染时主题正确:

import { useEffect } from 'react';

function MyApp({ Component, pageProps }) {
  useEffect(() => {
    const savedTheme = localStorage.getItem('theme');
    const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    const targetTheme = savedTheme || systemTheme;
    
    if (document.documentElement.dataset.theme !== targetTheme) {
      document.documentElement.dataset.theme = targetTheme;
    }
  }, []);

  return <Component {...pageProps} />;
}

export default MyApp;

注意事项

  • 全局样式必须基于data-theme属性编写,比如:
:root[data-theme='light'] {
  --bg: #fff;
  --text: #000;
}

:root[data-theme='dark'] {
  --bg: #1a1a1a;
  --text: #fff;
}

内容的提问来源于stack exchange,提问作者RikuS3n

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 18:13:39