必须写入localStorage并在页面加载初期同步到document.documentElement,否则刷新即丢失;因data-bs-theme是无状态DOM属性,需手动读取localStorage值并调用update()重算CSS变量。

必须写入 localStorage,且在页面加载初期就同步到 document.documentElement,否则刷新即丢失。
为什么只改 data-bs-theme 属性却记不住?
Bootstrap 的 data-bs-theme 是纯 DOM 属性,不带状态持久性。浏览器刷新后,HTML 恢复初始值,JS 也重执行——如果没主动从 localStorage 读取并设置,就永远回退到默认(通常是 light)。
常见错误包括:
- 只在点击按钮时写
localStorage.setItem('theme', 'dark'),但没在页面初始化时读 - 读了
localStorage却写到了document.body或某个 div,而没设到document.documentElement - 用了
document.documentElement.setAttribute('data-bs-theme', ...),但漏掉bootstrap.Theme.getOrCreateInstance().update(),导致 CSS 变量没重算
如何在 JS 加载第一时间恢复用户选择
关键不是“等 DOM 加载完”,而是“越早越好”,最好放在 <script></script> 标签内顶部执行(非事件监听里)。流程如下:
- 先检查
localStorage.getItem('theme')是否存在 - 有值就用它;无值则 fallback 到
window.matchMedia('(prefers-color-scheme: dark)').matches - 立即调用
document.documentElement.setAttribute('data-bs-theme', value) - 紧接着调用
bootstrap.Theme.getOrCreateInstance(document.documentElement).update() - 最后再更新 UI 元素(如按钮图标、文字)
注意:若用 UMD 方式引入 Bootstrap,需额外加载 bootstrap/js/dist/theme.js,否则 bootstrap.Theme 是 undefined。
localStorage 存什么、怎么读才安全
存字符串即可,推荐用 'light' / 'dark',避免布尔或数字类型造成歧义。读取时务必做类型判断:
const saved = localStorage.getItem('theme');
const theme = saved === 'dark' || saved === 'light' ? saved : (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
不要直接 JSON.parse,也不要用 == true 这类松散比较——localStorage 里所有值都是字符串。
容易被忽略的点:服务端渲染或静态 HTML 中, 标签不要预设 data-bs-theme="auto" 或空值,应固定为 data-bs-theme="light"。否则 JS 还没跑,浏览器已按深色变量渲染,可能造成闪屏或文字不可读。


















