必须使用bootstrap 5.3.0+版本,低于此版本(如5.2.x)不识别data-bs-theme属性;需在标签设置该属性,配合bootstrap.theme.getorcreateinstance().update()手动刷新css变量,并通过localstorage持久化主题状态。

必须用 Bootstrap 5.3.0+,否则 data-bs-theme 属性完全无效。 低于这个版本(比如 5.2.3)加了也白加,浏览器不会识别,CSS 变量也不会切换。
确认你用的是支持深色模式的 Bootstrap 版本
检查你引入的 CSS 和 JS 是否来自 5.3.0 或更高版本。CDN 推荐用 BootCDN 上的 5.3.3 或更新版链接,例如:
https://cdn.bootcdn.net/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css
旧版构建(如自己用 Sass 编译但没启用 $enable-dark-mode: true)也会缺失 _variables-dark.scss 编译结果,导致深色变量为空 —— 这时即使属性写了,背景、文字颜色也不变。
- 打开浏览器开发者工具,检查
:root下是否存在--bs-body-bg等深色变量(切到 dark 后应有明显值变化) - 如果用了自定义 Sass 构建,确认
bootstrap/scss/_root.scss被 import,且_variables-dark.scss已参与编译 - UMD 版本(
bootstrap.bundle.min.js)默认不导出bootstrap.Theme,需额外引入bootstrap/js/dist/theme.js才能调用update()
只改 标签的 data-bs-theme,别动
data-bs-theme 的作用域是 CSS 自定义属性,依赖 :root 选择器。加在 或某个 <div> 上,只会让局部组件(如 <code>.card)继承该属性,但 Toast、Offcanvas、Modal 等挂载到 document.body 的组件仍按根主题渲染,造成样式断裂。
- 正确写法:
document.documentElement.dataset.bsTheme = 'dark' - 错误写法:
document.body.dataset.bsTheme = 'dark'(无效) - 局部模式可用,但要清楚哪些组件会“逃逸”出父级作用域
改完属性后必须手动调用 bootstrap.Theme.getOrCreateInstance().update()
Bootstrap 不监听 DOM 属性变化。只设 dataset.bsTheme,CSS 变量不会自动重算 —— 页面看起来毫无反应,这是最常卡住的地方。
- ESM 环境下可直接:
new bootstrap.Theme(document.documentElement).update() - UMD 环境下需先确保
theme.js已加载,再用bootstrap.Theme.getOrCreateInstance(document.documentElement).update() - SSR 场景(如 Next.js)中,
update()必须放在useEffect或DOMContentLoaded后执行,且 DOM 必须已挂载
持久化与初始渲染不闪屏的关键点
服务端永远输出 ,JS 加载后再根据 localStorage.getItem('theme') 或 window.matchMedia('(prefers-color-scheme: dark)').matches 补值并 update()。否则 SSR 渲染时若直接输出 dark,而 JS 还没运行,用户会看到短暂白底黑字或黑底白字的“闪屏”。
-
localStorage存字符串'light'或'dark',别存布尔值 —— 后续加'auto'逻辑时语义更清晰 - 按钮点击时,先改
dataset.bsTheme,再localStorage.setItem(),最后.update()—— 顺序错会导致状态和 UI 不一致 -
prefers-color-scheme只用于 fallback 初始化,不能代替用户主动选择;它不会在系统偏好变更时自动触发页面重绘
真正容易被忽略的是:Theme 实例必须绑定到 document.documentElement,且 update() 是唯一触发 CSS 变量重计算的入口。漏掉这一步,所有配置都只是静态属性,页面不会变色。











