
直接用 prefers-color-scheme 媒体查询 + CSS 变量控制主题,是最轻量、最可靠、浏览器原生支持的方式。JavaScript 切换只是补充,不是必需。
怎么检测系统暗黑偏好
现代浏览器(Chrome 76+、Firefox 67+、Safari 12.1+)都支持 prefers-color-scheme 媒体查询,它能自动读取系统设置,无需 JS 就可响应。
常见错误是手动监听系统变化再 JS 注入 class——其实纯 CSS 就能搞定:
@media (prefers-color-scheme: dark) {
:root {
--bg: #121212;
--text: #e0e0e0;
}
}
@media (prefers-color-scheme: light) {
:root {
--bg: #ffffff;
--text: #333333;
}
}
- 这个方案零 JS、无闪屏、首次渲染即生效
- 不依赖用户点击或 localStorage,适合默认跟随系统
- 注意:Safari 在 iOS 13+ 和 macOS 10.15+ 才完整支持,旧版 Safari 会忽略该查询
怎么让用户手动切换主题
如果需要「明/暗/自动」三档切换,就得用 JS 管理 data-theme 属性,并同步 localStorage 和 class。
关键点不是“加 class”,而是避免样式冲突和重复计算:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 把
data-theme="dark"写在标签上,比挂 body 或 JS 动态切 class 更稳定 - 切换时必须同时更新
localStorage.setItem('theme', 'dark'),否则刷新丢失 - CSS 中优先级要压过
prefers-color-scheme:用[data-theme="dark"]而非仅@media - 示例逻辑:
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
}
// 页面加载时读取
const saved = localStorage.getItem('theme');
if (saved) {
setTheme(saved);
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
setTheme('dark');
} else {
setTheme('light');
}
为什么不能只靠 JS 切 class 控制颜色
单纯用 document.body.classList.toggle('dark') 是常见但危险的做法:
- 首屏渲染时 CSS 还没加载完,JS 晚于样式执行 → 白屏闪动(尤其网络慢时)
- 没有 fallback:如果 JS 报错或被拦截,主题彻底失效
- 无法利用浏览器的原生色感适配(比如 macOS 的深色菜单栏、iOS 的暗色通知中心)
- SEO 不友好:服务端无法预判主题,CSS-in-JS 方案更难 SSR
真正健壮的方案是:CSS 媒体查询兜底 + JS 增强控制,二者共存而非互斥。
暗黑模式下要注意哪些视觉陷阱
颜色不是简单「黑底白字」就完事。实际落地常踩这些坑:
-
border: 1px solid #ccc在暗色下几乎看不见,改用border: 1px solid rgba(255,255,255,0.1) - 图片、iframe、
<video></video>默认背景透明或白色,需显式设background: var(--bg) - 表单控件(
<input>、<select></select>)在 Safari 暗色下可能保留亮色边框,要用appearance: none+ 自定义 - 阴影(
box-shadow)在暗色下容易过重,建议用低透明度黑:box-shadow: 0 2px 8px rgba(0,0,0,0.2) - 别忘了
<code>、<pre class="brush:php;toolbar:false;"></pre>、<blockquote></blockquote>等语义元素的样式覆盖
最易被忽略的是 SVG 图标内联 fill 颜色和第三方组件(如地图、图表库)的暗色兼容——它们往往不响应 CSS 变量,得单独处理。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










