Web前端之样式中的light-dark函数,从媒体查询到颜色函数,从颜色到图片,light-dark打开CSS新时代、主题切换的暗黑模式到image的正解

Web前端之样式中的light-dark函数,从媒体查询到颜色函数,从颜色到图片,light-dark打开CSS新时代、主题切换的暗黑模式到image的正解


light-dark():把浅色/深色主题写进一行 CSS 里

在过去,做暗黑模式通常有两条路:一条是写@media (prefers-color-scheme: dark)去覆盖样式,另一条是用 JavaScript 或主题 class 自己管理切换状态。light-dark()的出现,把"同一个属性的浅色值与深色值"直接收拢成一个表达式,让主题色的表达更加声明式,也更适合组件化开发。它属于 CSS Color Module Level 5 中新增的能力,核心目标就是"根据当前 color-scheme 选择颜色"。


一、它到底是什么

light-dark()是一个 CSS 颜色函数。传入两个颜色值,第一个给浅色方案,第二个给深色方案;当用户的偏好是 light,或者没有明确偏好时,浏览器返回第一个值;当偏好是 dark 时,浏览器返回第二个值。MDN 明确说明了这个行为。


它的语义非常直接:"同一个地方,准备两套颜色,让浏览器自己选。" 这比把整个样式拆成两段媒体查询更紧凑,也更容易把主题逻辑压缩到组件内部。


二、先理解一个前提:color-scheme

light-dark()不是独立工作的。要让它真正生效,文档或容器必须声明color-scheme: light dark,通常放在 :root 上。MDN 给出的示例就是这样写的,并明确指出这是启用light-dark()的前提。


color-scheme的意义不只是"告诉浏览器要支持什么主题",它还会影响表单控件、滚动条以及系统色的使用方式,所以它不是一个可有可无的装饰属性,而是整套色彩体系的入口。


三、最小可用写法

css 复制代码
:root {
  color-scheme: light dark;
}

body {
  color: light-dark(#333b3c, #efefec);
  background-color: light-dark(#efedea, #223a2c);
}

这段代码的含义非常纯粹:浅色模式下,正文是深灰字、浅米色背景;深色模式下,正文反过来变浅,背景变深。MDN 就是用这个结构来演示light-dark()的。


在组件里使用自定义属性

css 复制代码
:root {
  color-scheme: light dark;
  --text-light: #111827;
  --text-dark: #f9fafb;
  --bg-light: #ffffff;
  --bg-dark: #111827;
}

.card {
  color: light-dark(var(--text-light), var(--text-dark));
  background: light-dark(var(--bg-light), var(--bg-dark));
}

light-dark()支持任何 color 值,所以 var()、rgb()、命名色、十六进制色都可以直接放进去。


四、它和 prefers-color-scheme 的关系

prefers-color-scheme适合写"整段规则切换",例如一个卡片、一整页、一个布局区块在浅色和深色之间做完整覆盖。MDN 对这个媒体特性给出的经典做法,就是默认浅色,然后在 @media (prefers-color-scheme: dark) 里覆盖成深色。


light-dark()更像是"把主题决策下沉到单个属性"。它不负责切换整套规则,而是负责把某个颜色值在浅/深之间选出来。两者并不冲突,而是适合不同粒度的主题控制。


从工程角度看,可以这样理解:
prefers-color-scheme:适合做"整页主题结构"
light-dark():适合做"颜色值原子切换"


五、为什么它值得用

第一,它让 CSS 更短。原来要写两段规则,现在常常一行就够。对于按钮、卡片、标签、边框、阴影这些只在颜色上有差异的元素,收益尤其明显。
第二,它很适合设计系统。设计系统里最常见的就是"同一个 token 在浅色与深色下要有不同值",light-dark()可以直接成为 token 表达式的一部分,而不是由 JS 再去二次计算。
第三,它更贴近浏览器原生的配色方案模型。因为它并不是自己发明一套主题状态,而是直接依赖color-scheme和用户偏好。


六、它的边界在哪里

light-dark()解决的是颜色选择,不是所有主题问题。布局变化、图片资源切换、复杂交互状态、不同主题下不同排版,这些仍然更适合用媒体查询或应用层状态控制。
另外,它依赖浏览器支持。按 Can I use 的数据,light-dark()作为 类型特性,在 Chrome 123+、Firefox 120+、Safari 17.5+、iOS Safari 17.5+、Opera 109+ 才进入支持区间;更早版本不支持。
Web Platform Features Explorer 还把它标记为 Baseline Newly Available,并给出"预计到 2026-11-13 才达到 Widely Available"的时间点,这说明它已经进入主流可用视野,但还没有完全成为"无脑默认"的普适能力。


七、正确的落地方式:先兜底,再增强

在生产环境里,更稳妥的写法是先给普通颜色兜底,再覆盖light-dark()

css 复制代码
.button {
  color: #111827;
  color: light-dark(#111827, #f9fafb);
  background-color: #ffffff;
  background-color: light-dark(#ffffff, #1f2937);
}

这样即便浏览器不支持light-dark(),页面也不会失去基本可读性。兼容性数据表明,旧版本 Chrome、Firefox、Safari 都存在不支持区间,所以保底写法很有价值。


八、组件级别的用法示例

css 复制代码
:root {
  color-scheme: light dark;
  --border-light: #d1d5db;
  --border-dark: #374151;
  --shadow-light: 0 1px 2px rgba(0, 0, 0, 0.08);
  --shadow-dark: 0 1px 2px rgba(0, 0, 0, 0.35);
}

.card {
  border: 1px solid light-dark(var(--border-light), var(--border-dark));
  box-shadow: light-dark(var(--shadow-light), var(--shadow-dark));
  background: light-dark(#ffffff, #111827);
  color: light-dark(#111827, #f9fafb);
}

这种写法适合卡片、面板、按钮、输入框等组件。逻辑集中,视觉表达清晰,而且不会把整个主题系统都绑在 JavaScript 上。light-dark()的 formal syntax 也明确允许它接受两个 值。


九、一个容易被忽略的细节:不要随便覆盖用户偏好

MDN 在light-dark()的示例里特别展示了把某个 section 强制设为color-scheme: lightcolor-scheme: dark,但同时也提醒:一般不应该这样做,因为用户已经选定的偏好应当优先尊重。这个做法更适合演示,不适合作为默认策略。
也就是说,真正推荐的默认思路是:尊重系统偏好,让浏览器决定浅/深模式;只有在非常明确的局部场景才局部覆盖。


十、支持图片的发展路程

这部分最值得单独说清楚。MDN 的 formal syntax 已经把light-dark()扩展到了light-dark-image分支,而且该分支允许 image | none 这样的值。也就是说,标准语法层面已经预留了"根据color-scheme切换图片"的入口。
不过,当前主流兼容性数据主要展示的是light-dark()作为 的支持情况;Can I use 也在这个维度上给出了清晰的浏览器支持表。就工程实践而言,图片切换这件事今天(2026-03-30)仍然更适合用@media (prefers-color-scheme)来做,而不是把生产逻辑押在图片分支上。


图片切换在现实项目里通常还是这样写更稳

css 复制代码
.hero {
  background-image: url("/images/hero-light.jpg");
}

@media (prefers-color-scheme: dark) {
  .hero {
    background-image: url("/images/hero-dark.jpg");
  }
}

这是目前更成熟、可控、易维护的方案。light-dark()的图片能力可以关注,但不建议现在就把它当成跨浏览器稳定方案。


十一、一句话总结

light-dark()的本质,是把浅色与深色两套颜色直接写在同一个 CSS 值里;它依赖color-scheme: light dark,适合做颜色级别的主题切换,已经进入主流浏览器支持区间,但图片分支目前更适合视作规范层面的前瞻能力。


十二、可直接复用的项目建议

真正上项目时,可以按这个顺序落地:先加:root { color-scheme: light dark; },再在颜色属性上逐步替换成light-dark(),最后保留普通颜色作为兜底。这样既能享受新语法的简洁,也不会因为兼容问题把页面弄坏。

相关推荐
酉鬼女又兒2 小时前
零基础快速入门前端蓝桥杯Web考点深度解析:var、let、const与事件绑定实战(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·javascript·职场和发展·蓝桥杯·es6·html5
宁雨桥2 小时前
前端项目实现光暗主题切换的完整方案
前端
happymaker06262 小时前
vue指令扩展以及监视器的使用
前端·javascript·vue.js
一只小阿乐2 小时前
vue前端处理流式数据
前端·javascript·ai·大模型·全栈开发·agentai
问道飞鱼3 小时前
【技术方案】面向 Web 系统的《全栈灰度部署方案设计》
前端·全栈·灰度发布
꧁꫞꯭零꯭点꯭꫞꧂3 小时前
前端面试题3
开发语言·前端·javascript
ZC跨境爬虫3 小时前
Base64编码详解(含JS_Python实现+实战逆向案例)
前端·javascript·python
FuckPatience3 小时前
Halcon 寻找方形Mark
前端·javascript·数据库