用data-theme控制主题最轻量可控:JS设置html的data-theme属性,CSS用[data-theme="dark"]覆盖CSS变量,localStorage持久化用户选择,优先级高于prefers-color-scheme。

怎么用 data-theme 控制页面主题
靠 HTML 元素上的 data-theme 属性配合 CSS 自定义属性,是最轻量、最可控的暗色模式实现方式。它不依赖 JS 框架,也不强求用户系统偏好,适合需要手动切换或记住用户选择的场景。
核心逻辑是:JS 改 ,CSS 用属性选择器匹配并覆盖变量值。
-
data-theme建议只设在上,避免嵌套组件重复判断 - 不要用
theme或mode这类泛化名,data-theme是社区事实标准,部分浏览器 DevTools 会识别 - 初始值建议设为
data-theme="light",否则 SSR 渲染时可能闪白/闪黑
CSS 里怎么写暗色变量规则
别写两套完全独立的样式,用 :root 定义默认(亮色)变量,再用 [data-theme="dark"] 覆盖——这样维护成本低,也方便后续加第三种主题。
示例:
立即学习“前端免费学习笔记(深入)”;
:root {
--bg: #fff;
--text: #333;
--border: #e0e0e0;
}
[data-theme="dark"] {
--bg: #1e1e1e;
--text: #e0e0e0;
--border: #333;
}
body {
background-color: var(--bg);
color: var(--text);
border-color: var(--border);
}
- 所有颜色相关 CSS 属性都应基于
var(--xxx),而不是直接写死值 - 避免在
[data-theme="dark"]里重写整套布局或字体大小,那不是主题该干的事 - 图片、SVG 的颜色如果用
currentColor,会自动随--text变,比硬编码fill="#333"更省心
切换时 JS 怎么存和读取主题
用户点一次“切暗色”,得记下来,不然刷新就回亮色。用 localStorage 最稳妥,比 cookie 简单,比 sessionStorage 持久。
- 写入:
localStorage.setItem('theme', 'dark') - 读取:
localStorage.getItem('theme'),但注意返回的是字符串,要判空和大小写 - 首次加载时,优先读
localStorage;没值再 fallback 到matchMedia('(prefers-color-scheme: dark)') - 别在
DOMContentLoaded之后才设data-theme,否则页面会先闪一下亮色——建议内联一小段 script 放在里执行
为什么 prefers-color-scheme 不能直接当唯一方案
它只反映系统设置,用户点了“切换”按钮却没反应,体验就是断的。而且 iOS Safari 在某些版本里对这个媒体查询的支持有延迟或不触发。
- 不能把
@media (prefers-color-scheme: dark)当成主题开关——它适合做兜底,不适合做主控 - 如果同时用了
prefers-color-scheme和手动切换,得确保 JS 设置的data-theme优先级更高,否则媒体查询会把用户选择覆盖掉 - 部分屏幕阅读器或高对比度模式下,
prefers-color-scheme可能返回no-preference,这时按逻辑应走亮色,但得测试是否真符合可访问性预期
真正麻烦的不是切一次,而是切完之后所有动态插入的 DOM、第三方组件、iframe 里的内容要不要同步——这些地方往往漏掉 data-theme 透传,或者没监听 storage 事件更新自身状态。



















