标签本身不感知暗黑模式,需靠的media="(prefers-color-scheme: dark)"等合法媒体查询匹配系统偏好,暗色必须置于亮色之前,且必须保留无media的作为兜底,否则无匹配时将空白或404。

picture 标签本身不感知暗黑模式,必须靠 media 属性配合 prefers-color-scheme
浏览器不会自动根据系统主题切换 <picture></picture> 里的图片——它只是个容器,切换逻辑全靠你写的 media 查询。关键不是标签怎么写,而是 source 元素的 media 值是否正确匹配用户偏好。
-
media="(prefers-color-scheme: dark)"对应暗黑模式,只在系统设为深色时生效 -
media="(prefers-color-scheme: light)"对应亮色模式,注意:这不是默认回退项,未匹配时会跳过 - 必须保留一个不带
media的<img>作为兜底,否则无匹配时页面显示空白或加载失败 - 顺序很重要:
<source></source>按从上到下匹配,第一个满足media条件的生效,其余忽略
正确写法:两个 source + 一个无 media 的 <img>
下面是最小可用结构,支持 Safari、Chrome、Firefox(96+)和 Edge:
<picture><source srcset="logo-dark.webp" type="image/webp" media="(prefers-color-scheme: dark)"><source srcset="logo-light.webp" type="image/webp" media="(prefers-color-scheme: light)"> @@##@@ </source></source></picture>
说明:
- 两个
<source></source>分别指定深/浅色图,type可省略,但加上能避免浏览器加载不支持格式的资源 -
<img src="logo-fallback.png" alt="Logo">的src必须是真实可加载的图片,不能留空或写占位符路径,否则暗黑/亮色都未命中时会触发 404 或空白 - 不要把
media="(prefers-color-scheme: no-preference)"加进来——它极少触发,且行为不可靠,实际项目中基本不用
常见错误:CSS 覆盖了 <img> 导致切换失效
很多人用 CSS 给 <img> 设置 display: none 或透明度来“隐藏”备用图,这会破坏 <picture></picture> 的语义和加载逻辑。
-
<picture></picture>决定哪个资源被加载,不是哪个元素被显示;display: none不阻止浏览器下载<img> - 如果想做过渡动画,应在
<img src>上监听load事件,而非依赖 CSS 显隐控制 - 不要给
<source></source>加class或style——它们不渲染,加了也没用 - 调试时打开 DevTools → Network 标签页,切主题后刷新,看实际加载的是哪张图,比肉眼判断更准
兼容性与 fallback 注意事项
prefers-color-scheme 在 iOS Safari 13+、Android Chrome 76+ 才稳定支持。旧版本浏览器会直接忽略 media,走 <img> 的 src。
- 如果你的
<img>指向的是亮色图,那旧浏览器看到的就是亮色图,这是合理预期 - WebP 格式在 Safari 14+ 才完全支持,iOS 14 以下用户可能加载失败,所以
<img>的src最好用 PNG 或 JPEG - 不要依赖 JavaScript 动态插入
<source></source>——服务端渲染或静态 HTML 中写死更可靠,JS 注入容易因执行时机导致闪烁或加载两次
真正麻烦的不是怎么写,而是得同时考虑:系统主题是否可读、浏览器是否识别、fallback 图是否可用、网络是否加载了正确的资源——四个环节缺一不可。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











