现代网站若只提供单一配色,在用户开启系统深色外观时往往会出现刺眼白底或不可读文字。将CSS颜色体系与媒体查询结合,是低成本实现深色模式自适应的主流做法。其本质是把颜色从具体数值抽象为语义变量,再根据环境切换变量取值。

用CSS自定义属性建立可切换的调色板
过去很多页面直接把背景写成#ffffff、文字写成#333333,这种硬编码方式让后期适配深色模式变得繁琐。更合理的做法是利用CSS自定义属性(也称CSS变量)声明一套语义化颜色,例如--bg-color表示背景、--text-color表示正文。在:root中给出默认值,页面各处统一通过var()函数引用,不直接出现具体色值。
这样的结构带来明显好处:当我们需要切换主题时,只需改变量的值,不用逐个修改上百个规则。下面的代码展示基础调色板定义方式,把亮色作为默认,保证不支持媒体查询的旧浏览器也能正常显示。
:root {
--bg-color: #ffffff;
--text-color: #212121;
--border-color: #e0e0e0;
--link-color: #1565c0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
}
a {
color: var(--link-color);
}
从维护角度看,语义变量还能避免颜色含义模糊。比如设计师说“次要文字再淡一点”,开发者直接调整--text-secondary即可,不必在多处寻找相同色值。这种抽象是后续媒体查询切换的前提条件。
通过prefers-color-scheme媒体查询感知系统设置
CSS提供的prefers-color-scheme媒体特性可以检测用户操作系统当前是亮色还是深色外观。它的值通常为light或dark,部分环境支持no-preference。我们在样式表中追加一个@media块,在其中重定义同一批变量,浏览器便会自动采用匹配系统的数值。
关键在于媒体查询块里只覆盖变量,不重写具体选择器。这样无论系统怎么切,结构样式都不动。以下示例在深色模式下把背景改为近黑、文字改为浅灰,同时调亮链接色以保对比度。
@media (prefers-color-scheme: dark) {
:root {
--bg-color: #121212;
--text-color: #e0e0e0;
--border-color: #333333;
--link-color: #82b1ff;
}
}
@media (prefers-color-scheme: light) {
:root {
--bg-color: #ffffff;
--text-color: #212121;
--border-color: #e0e0e0;
--link-color: #1565c0;
}
}
有些开发者担心默认写在:root里的亮色值会和light查询重复,其实显式写出light块能提升可读性,也方便以后扩展如高对比度模式。要注意媒体查询本身不负责颜色计算,它只是条件开关,真正的颜色适配仍依赖前一步的变量引用。
处理图片阴影与表单控件等细节差异
仅切换背景文字还不够,深色模式下若图片带白边或阴影过重会显得突兀。对于透明底插图,可用filter: invert()或brightness()临时反转;对于照片类则不建议反转,可准备两套src或用picture元素配合媒体查询。边框颜色也应随变量走,否则会出现亮色细线浮在黑底上。
原生表单控件如<input>、<textarea>在暗色系统里部分浏览器会自动着色,但老版本不会。稳妥方案是给这些控件也加上background-color: var(--bg-color)与color: var(--text-color),并显式设置border-color。下面代码演示输入框在两种模式下的统一处理。
input, textarea {
background-color: var(--bg-color);
color: var(--text-color);
border: 1px solid var(--border-color);
padding: 8px;
}
@media (prefers-color-scheme: dark) {
input, textarea {
border-color: var(--border-color);
}
}
阴影在暗底上容易看不见或显脏,可把box-shadow的透明度降低,或改用细微描边。最终测试时建议直接在系统设置里切换外观,观察页面是否无刷新平滑变色。若使用构建工具,也可将变量提取到独立文件,便于设计师调整色板而不碰逻辑样式。
对比传统多套样式表方案的优劣
在没有自定义属性以前,团队常为深色模式新建dark.css,用JS判断后动态加载。这种做法导致规则重复、体积翻倍,且容易漏改。变量加媒体查询的方案让同一份规则容纳双主题,CSS体积更小,切换由浏览器原生完成无脚本依赖。
当然变量方案要求浏览器支持CSS自定义属性,好在主流版本均已支持;若需兼容极旧环境,可用PostCSS插件把变量编译为静态值并输出带媒体查询的兜底包。总体来看,颜色与媒体查询结合是当前最平衡的工程选择,既满足用户系统级偏好,也减轻长期维护负担。