最轻量且无需JS的深色模式方案是优先使用prefers-color-scheme媒体查询,再用localStorage+dark类实现用户手动覆盖;避免color-scheme meta标签误用及内联样式硬改,图标和图片需双资源适配。
prefers-color-scheme 检测系统偏好,最轻量且无需 JS现代浏览器(Chrome 76+、Firefox 67+、Safari 12.1+)原生支持 prefers-color-scheme 媒体查询,能直接读取用户操作系统级的深色/浅色设置。这是加夜间模式的第一道防线,也是最可靠的基础。
change 事件才实时更新)@media (prefers-color-scheme: dark) {
:root {
--bg: #1e1e1e;
--text: #e0e0e0;
}
}
@media (prefers-color-scheme: light) {
:root {
--bg: #ffffff;
--text: #333333;
}
}
localStorage + class 切换,支持用户手动覆盖系统设置用户可能想“反系统”:比如系统设为浅色,但希望网页用深色。这时必须提供开关按钮,并把选择持久化到 localStorage,否则刷新就丢。
style 标签或内联样式切换——难以维护、无法继承、CSS 优先级混乱 或 添加 dark class,再用 CSS 层叠控制样式localStorage 和 class,还要处理 prefers-color-scheme 与手动设置的优先级关系function setDarkMode(isDark) {
if (isDark) {
document.documentElement.classList.add('dark');
localStorage.setItem('theme', 'dark');
} else {
document.documentElement.classList.remove('dark');
localStorage.setItem('theme', 'light');
}
}
// 初始化:先看 localStorage,再 fallback 到 prefers-color-scheme
const saved = localStorage.getItem('theme');
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (saved === 'dark' || (!saved && systemPrefersDark)) {
setDarkMode(true);
} else {
setDarkMode(false);
}
color-scheme meta 标签和强制重绘陷阱 只影响浏览器 UI(如地址栏、滚动条),**不会改变你的页面样式**。别指望它替代 CSS。
document.body.style.backgroundColor 这类内联样式硬改?会导致 CSS 变量失效、媒体查询被绕过、动画卡顿getComputedStyle 或强制重排(如读写 offsetHeight)可能引发布局抖动,尤其在 scroll 或 toggle 事件中box-shadow 和半透明背景(rgba(0,0,0,0.1) 在黑底上几乎不可见)filter: brightness(0.8) contrast(1.2) 看似简单,但对图标、图表、照片效果极不稳定:可能让灰度图变糊、让红色失真、让 SVG 渐变断裂。
立即学习“前端免费学习笔记(深入)”;
logo、按钮 icon),准备两套资源,用 picture + media 切换.dark svg path { fill: var(--icon-dark); } 控制颜色background-image: image-set(...)(支持有限)或 JS 动态换 src
真正麻烦的是第三方内容(如 embed 的视频、iframe 广告、富文本里的 )——它们不受你 CSS 控制,得靠 invert() + hue-rotate() 补救,但代价是色彩失真。这种边界情况,往往比开关本身更耗时间。