bootstrap 5.3.0+ 原生支持深色模式,需在 标签加 data-bs-theme="dark" 并调用 bootstrap.theme.getorcreateinstance().update() 刷新变量,同时注意版本、加载完整性、ssr 时机、持久化逻辑及局部模式限制。

直接加 data-bs-theme="dark" 就行,但必须满足三个前提
Bootstrap 5.3.0+ 原生支持深色模式,不需要 JS 库、不用重写 CSS 变量、也不用自己配 SCSS —— 只要在 标签上加一个属性就生效。
但这个“简单”是有硬性门槛的:
- 版本必须 ≥
5.3.0(旧版如 5.2.x 完全不识别data-bs-theme) - 必须加在
根元素上,加在或某个<div> 里只影响局部,且部分组件(如 <code>Toast、Offcanvas)可能不响应 - 确保加载的是完整 Bootstrap CSS(含
_variables-dark.scss编译结果),CDN 推荐用 BootCDN 上的5.3.3或更高版 - 点击按钮后只改属性,没调
bootstrap.Theme.getOrCreateInstance(document.documentElement).update() - 用了 UMD 版本(如
bootstrap.bundle.min.js)却误以为bootstrap.Theme是全局构造函数 —— 实际上它只在 ESM 构建中导出;UMD 下需先确认是否已正确引入bootstrap/js/dist/theme.js - 在 SSR 环境(如 Next.js)中,服务端渲染时 JS 还没执行,
update()必须放在useEffect或DOMContentLoaded后,且要等 DOM 挂载完成 - 服务端永远输出
(不猜用户偏好) - JS 加载后立即读
localStorage.getItem('theme')或 fallback 到window.matchMedia('(prefers-color-scheme: dark)').matches - 设置
document.documentElement.dataset.bsTheme后,立刻调new bootstrap.Theme(...).update() - 每次切换按钮点击,都要同步写入
localStorage,且存字符串'light'或'dark'(别存布尔值,后续扩展'auto'会卡住) -
navbar是个特例:它有自己的navbar-dark/navbar-light类,和data-bs-theme并不完全正交;混用时容易文字/背景对比度失效(比如data-bs-theme="dark"+navbar-light导致白字白底) - 自定义 SCSS 中若覆盖了
$body-bg等变量,记得同时在_variables-dark.scss里配对修改,否则局部模式下颜色会错乱
bootstrap.Theme.getOrCreateInstance().update() 是切换时必调的刷新动作
你改了 document.documentElement.dataset.bsTheme = 'dark',页面却没变?大概率是漏了这一步:Bootstrap 不会监听 DOM 属性变化自动重算 CSS 变量,得手动触发更新。
常见错误场景:
用户偏好持久化不能只靠 localStorage.setItem('theme', 'dark')
存值只是第一步。真正麻烦的是读取时机和初始渲染一致性 —— 否则会出现「闪白」或「闪黑」。
关键逻辑链:
局部深色模式要小心组件继承与样式泄漏
虽然可以在某个卡片上写 <div class="card" data-bs-theme="dark"> 实现局部暗色,但要注意:
<ul>
<li>子组件如 <code>btn、form-control 会继承父级 data-bs-theme,但像 dropdown-menu 这类脱离文档流的浮层,仍受根元素主题控制,除非显式再加一次属性
最常被忽略的一点:CSS 变量刷新不是原子操作。哪怕你正确调用了 .update(),如果页面里有大量动态插入的组件(比如通过 innerHTML 注入的卡片),它们的样式可能仍沿用旧变量值 —— 这时候得考虑在插入后手动触发一次 update(),或者改用事件委托统一处理。











