<picture> 标签本身不支持暗黑模式自动切换,仅响应屏幕尺寸和像素密度;实现暗黑/亮色背景图切换应优先使用 CSS @media (prefers-color-scheme: dark) 配合 background-image,轻量、无 JS、兼容性好。

picture 标签本身不支持暗黑模式自动切换
直接用 <picture> 无法根据系统暗黑模式(prefers-color-scheme)自动选图——它只响应屏幕尺寸(media 属性)和像素密度(srcset),不识别颜色方案。想实现暗黑/亮色背景图切换,得靠 CSS 的 @media (prefers-color-scheme: dark) 配合 background-image,或者用 <picture> + JS 监听 matchMedia 手动切换,但后者对「背景图」意义不大(<picture> 是为 <img> 服务的,不是为 CSS 背景设计的)。
用 CSS 媒体查询 + background-image 最简可行
如果目标是让一个容器(比如 <div class="hero">)在暗黑模式下显示不同背景图,CSS 方案最轻量、无 JS、兼容性好(Chrome 87+、Firefox 90+、Safari 14+ 支持 prefers-color-scheme):
.hero {
background-image: url('/images/bg-light.jpg');
background-size: cover;
}
@media (prefers-color-scheme: dark) {
.hero {
background-image: url('/images/bg-dark.jpg');
}
}
- 不需要改 HTML 结构,纯 CSS 控制
- 两张图会按需加载(浏览器只下载匹配当前 scheme 的那张)
- 注意:确保路径正确,且服务器允许跨 scheme 加载(一般没问题)
- 若用 WebP/AVIF 等格式,可叠加
@supports做渐进增强,但非必需
强行用 picture 实现“类背景图”效果(仅限 img 场景)
如果你必须用语义化 <img>(比如 banner 图需要 SEO、alt 文本、宽高比控制),且希望它随暗黑模式切换,可以用 <picture> 配合 media 查询 prefers-color-scheme:
<picture> <source media="(prefers-color-scheme: dark)" srcset="/images/banner-dark.webp" type="image/webp"> <source media="(prefers-color-scheme: dark)" srcset="/images/banner-dark.jpg" type="image/jpeg"> <source media="(prefers-color-scheme: light)" srcset="/images/banner-light.webp" type="image/webp"> <source media="(prefers-color-scheme: light)" srcset="/images/banner-light.jpg" type="image/jpeg"> <img src="/images/banner-light.jpg" alt="Banner description"> </picture>
-
media属性支持prefers-color-scheme,现代浏览器已广泛支持 - 务必把
<source>按优先级从高到低排列(WebP 在前,fallback 到 JPEG) -
<img>的src是最终 fallback,建议设为 light 模式图,避免暗黑模式下无图回退失败 - 注意:Safari 对
prefers-color-scheme在<source>中的支持曾有延迟(iOS 15.4+、macOS 12.3+ 稳定)
JS 监听切换 + 动态替换 background-image(适合运行时重绘)
当需要更复杂逻辑(比如用户手动覆盖系统设置、或背景图需结合其他状态)时,可用 JS 监听并操作 style:
立即学习“前端免费学习笔记(深入)”;
const hero = document.querySelector('.hero');
const darkModeMedia = window.matchMedia('(prefers-color-scheme: dark)');
function updateBg() {
if (darkModeMedia.matches) {
hero.style.backgroundImage = "url('/images/bg-dark.jpg')";
} else {
hero.style.backgroundImage = "url('/images/bg-light.jpg')";
}
}
darkModeMedia.addEventListener('change', updateBg);
updateBg(); // 初始化
- 注意:内联
style.backgroundImage会覆盖 CSS 中的声明,慎用;推荐切换 class(如hero--dark)更可控 - 不要在每次 resize 或 scroll 里重复调用
matchMedia,只监听change事件即可 - 服务端渲染(SSR)场景下,首次 HTML 渲染无法感知客户端 scheme,需预留占位或用
data-属性标记后由 JS 补全
真正容易被忽略的是:暗黑模式切换可能发生在页面已加载之后,且部分旧版浏览器(如 Chrome prefers-color-scheme 媒体查询,这时候 fallback 到 light 图是安全的,但别指望它能“自动变暗”。



















