@media (prefers-color-scheme) 需写在亮色规则之后、避免嵌套作用域、确保 css-in-js 支持透传;ssr 首屏需 js 同步 data-color-scheme;:root 变量重定义须顺序正确;color-scheme: light dark 必须声明以适配原生控件。

如何用 @media (prefers-color-scheme) 切换 CSS 主题
直接写 @media (prefers-color-scheme: dark) 就能捕获系统暗黑偏好,但关键不是“能不能”,而是“在哪写、怎么覆盖、会不会被后加载的样式冲掉”。它本质是媒体查询,优先级和普通 CSS 规则一致,不自动提升权重。
- 必须把暗黑规则写在对应亮色规则之后,否则
dark样式可能被前面的亮色声明覆盖 - 不要嵌套在
@layer或第三方 CSS 框架的未导出作用域里,否则可能根本不起效 - 若用 CSS-in-JS(如 Emotion),需确认其支持原生媒体查询透传,部分旧版本会剥离
prefers-color-scheme
为什么 prefers-color-scheme 有时不触发
常见现象是改了系统设置,页面却没变——大概率不是代码问题,而是浏览器缓存或加载时机问题。该媒体查询只在初始渲染和系统主题切换时响应,不会回溯已渲染的元素。
- 开发时用 Chrome 的
Rendering面板手动切换prefers-color-scheme,比反复改系统设置更可靠 - 如果页面用 SSR 渲染(如 Next.js),服务端无法读取客户端偏好,首屏会按默认主题(通常是亮色)输出,JS 加载后才补上暗色类;此时需配合
data-color-scheme属性 + JS 同步 - Safari 对
prefers-color-scheme的支持从 v12.1 开始,低于此版本返回no-preference,不能当light用
用 :root 变量配合 @media 管理主题色是否安全
安全,但要注意变量作用域和重定义顺序。CSS 自定义属性本身是继承的,:root 定义的变量全局可用,但在媒体查询里重定义,仅对匹配条件下的后续计算生效。
:root {
--bg: #fff;
--text: #000;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #eee;
}
}
body { background: var(--bg); color: var(--text); }
- 变量名必须完全一致,
--BG和--bg是两个变量 - 不要在媒体查询里用
!important覆盖变量值,无效 - 若同时用
class="dark"手动强制主题,需确保该 class 的:root重定义在媒体查询之后,否则会被覆盖
要不要用 color-scheme: dark 声明
要,但只用于表单控件和滚动条等原生元素。它不控制你的 CSS,只告诉浏览器:“请把 <input>、<select></select>、<textarea></textarea> 这些默认控件按暗黑风格渲染”。不加的话,即使你写了完整暗黑 CSS,原生控件仍可能是亮色。
立即学习“前端免费学习笔记(深入)”;
- 加在
:root或html上即可::root { color-scheme: light dark; } - 只写
dark会禁用亮色模式下的原生控件适配,应始终写成light dark - 该属性不影响自定义组件,也不影响
background或color等常规属性










