Bootstrap 5.3+ 通过设置 <html> 标签的 data-bs-theme=”dark” 手动切换深色模式,需配合官方 CSS、localStorage 保存选择,并确保 CSS 使用变量而非硬编码颜色。
怎么用 Bootstrap 5 的 data-bs-theme 切换深色模式
bootstrap 5.3+ 原生支持 data-bs-theme="dark",但不是靠 js 自动监听系统偏好,而是需要你手动切换 html 根节点的这个属性值。浏览器会根据该属性触发 css 变量重计算,前提是你的 css 支持(比如用了 bootstrap 官方深色主题 css)。
常见错误是只改了 <body> 或某个容器的 data-bs-theme,结果没效果——必须改 <html> 标签,因为 Bootstrap 的深色变量作用域基于 :root。
- 确保引入的是 Bootstrap 5.3.3+ 官方 CSS(CDN 或本地构建),旧版本不支持
data-bs-theme - 深色样式依赖 CSS 自定义属性(
--bs-body-bg等),不能只靠 class 切换 - 如果用 Sass 自定义主题,需启用
$enable-dark-mode: true并重新编译
点击图标按钮时,如何正确触发主题切换
核心就是两件事:改 <html> 的 data-bs-theme 属性 + 保存用户选择到 localStorage。别用 class 切换,也别试图重载 CSS 文件。
示例逻辑:
document.getElementById('theme-toggle').addEventListener('click', () => {const html = document.documentElement; const current = html.getAttribute('data-bs-theme') || 'light'; const next = current === 'light' ? 'dark' : 'light'; html.setAttribute('data-bs-theme', next); localStorage.setItem('theme', next); });
- 务必用
document.documentElement,不是document.body - 初始化时从
localStorage读取,而不是只看prefers-color-scheme,否则用户上次选择会被覆盖 - 图标切换建议用 Font Awesome 的
fa-sun/fa-moon,配合classList.toggle()更新 icon
为什么加了 data-bs-theme 还是不生效
最常踩的坑是 CSS 加载顺序和变量覆盖。Bootstrap 深色模式依赖 CSS 中的 @media (prefers-color-scheme: dark) 和 [data-bs-theme="dark"] 双重规则,但如果自定义 CSS 写在 Bootstrap 之后且硬编码了 background-color: #fff,就会把变量值直接干掉。
- 检查浏览器开发者工具里,
:root下的--bs-body-bg值是否随data-bs-theme改变而变化 - 确认没在 CSS 里写死颜色(比如
.card {background: white;}),应改用var(--bs-body-bg) - 如果你用的是 Bootstrap CDN,必须用完整版 CSS,精简版(如 bootstrap.min.css 不含深色变量)不包含暗色规则
要不要监听 prefers-color-scheme 自动同步
可以监听,但仅用于首次加载时 fallback,不能替代用户主动选择。因为 prefers-color-scheme 是系统级设置,用户点了切换按钮,就说明他明确要覆盖系统偏好。
推荐做法:页面加载时,先读 localStorage;没值再查 matchMedia('(prefers-color-scheme: dark)');最后才设 data-bs-theme。
- 监听
matchMedia变化并自动切主题?没必要,而且容易和用户手动选择冲突 - 移动端 Safari 对
data-bs-theme的响应有约 100ms 延迟,别用它做动画或过渡依赖 - 如果项目用了 SSR(如 Next.js),服务端无法访问
localStorage或matchMedia,得靠客户端 hydration 后再应用
主题切换真正难的不是代码几行,而是 CSS 变量能不能穿透所有组件、有没有被硬编码值截断、以及用户选择是否被 localStorage 和初始化逻辑可靠承接。这些地方漏一个,点十次图标也没用。