prefers-color-scheme媒体查询必须写在:root默认声明之后,否则深色变量会被浅色默认值覆盖;需独立书写、置于css靠后位置,并配合和系统语义色确保表单控件及svg图标正确响应。

prefers-color-scheme 媒体查询必须写在 :root 默认声明之后
很多人写了 @media (prefers-color-scheme: dark) 却没生效,根本原因是 CSS 层叠顺序错了。浏览器按书写顺序解析,如果深色规则写在浅色变量定义之前,它会被后续的浅色默认值覆盖;旧版 Safari 甚至直接跳过嵌套或前置的媒体查询。
正确做法是:先在 :root 中完整声明所有变量的浅色默认值,再把深色覆盖块放在文件靠后位置,且必须独立、不嵌套:
:root {
--color-bg: #ffffff;
--color-text: #1d1d1f;
--color-border: #d2d2d7;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #000000;
--color-text: #e0e0e0;
--color-border: #3a3a3c;
}
}
- 漏掉任意一个变量(比如只改
--color-bg却忘了--color-border),用到它的组件就会 fallback 到浏览器默认色,可能突然变白或消失 - 不要写成
@media (max-width: 768px) { @media (prefers-color-scheme: dark) { ... } }—— 这种嵌套在 Safari 12.1–15.x 中完全无效 -
@media只在页面加载时读取一次系统偏好,切换系统主题后不会自动重绘,这不是 bug,是设计行为
color-scheme meta 标签是表单控件适配的硬性前提
写了 color-scheme: light dark 却发现 <input> 还是白底黑字?大概率是因为缺了 <meta name="color-scheme" content="light dark">。这个 <meta> 是触发浏览器 UA 自动渲染深色表单控件(如输入框背景、滚动条 thumb、<select></select> 下拉箭头)的开关,CSS 层的 color-scheme 声明无法替代它。
- iOS Safari 和部分 WebView 必须依赖该
<meta>才能启用原生控件深色样式 -
color-scheme本身不改变你写的background-color或color,它只影响浏览器内置样式:表单边框、<progress></progress>轨道、::-webkit-scrollbar等 - 建议直接加在
开头:<meta name="color-scheme" content="light dark">,无需 JS 干预
系统语义色比十六进制更稳,但不能透明
用 Canvas 和 CanvasText 替代 #000000、#ffffff,能让颜色随系统高对比度、深色/浅色设置自动微调亮度与饱和度。但它们不支持 alpha,写 CanvasAlpha 无效。
- 需要半透效果时,Chrome 111+ 可用
color-mix(in srgb, CanvasText 70%, transparent),老版本需 fallback 到变量(如--text-primary-alpha: rgba(224, 224, 224, 0.7)) -
background-color: Canvas比#121212更可靠,尤其在 Windows 高对比度模式下不会失真 - 内联 SVG 图标不会自动反色,必须用
fill: currentColor或fill: var(--icon-fill)才能响应主题变化
:root 是唯一能确保全局继承的变量作用域
把主题变量写在 .dark 类或 body 里,<input>、<button></button>、伪元素(如 ::placeholder)、Shadow DOM 内部都读不到——因为 CSS 自定义属性靠继承传播,而只有 :root(即 元素)能保证任意后代都能通过 var(--bg-color) 正确求值。
-
.dark { --bg-color: #121212; }→<input>若不在.dark包裹范围内,就 fallback 到透明或浏览器默认色 - JS 切换主题时,只操作
document.documentElement.classList.toggle('dark'),绝不要用style.setProperty()直接改变量 —— 后者会破坏@media的逻辑,且无法被伪元素继承 - 初始化必须早于首屏渲染:把 JS 放在
内的<script></script>中执行,别等DOMContentLoaded
<input> 不看你的 .card 类,::placeholder 不继承 body 上的变量,<svg></svg> 里的 fill 也不会自动跟着 color-scheme 变。每个环节都要显式对齐作用域和继承链。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











