media属性仅在<picture>中有效,用于按CSS媒体查询条件选择图片源;在<video>或<audio>中被忽略,且必须带括号、正确排序、配合viewport和display规范使用。

media属性只在<picture>里真正起效
media 属性不是万能开关,它在 <video> 或 <audio> 中基本被浏览器忽略——Chrome、Firefox、Safari 都不按它做条件加载。你写 <source src="vid.mp4" media="(min-width: 768px)">,视频照样全量预加载,甚至可能多下几个源。唯一稳定生效的上下文是 <picture>:浏览器按顺序匹配第一个 media 为 true 的 <source>,然后加载其 srcset 或 src,其余跳过。
常见错误是把 <picture> 当成通用响应式容器,试图往里塞视频或音频——不行,<picture> 只接受图片资源,<source> 的 media 在这里才具备语义化选择能力。
media值必须是合法CSS媒体查询,括号不能少
写 media="max-width: 767px" 是无效的,浏览器直接当 not all 处理,该 <source> 被跳过。正确写法必须带括号:media="(max-width: 767px)"。空格、括号配对、单位(px)缺一不可。
-
media="(min-width: 1200px) and (orientation: landscape)"✅ 同时满足两个条件 -
media="(prefers-color-scheme: dark), (prefers-reduced-motion: reduce)"✅ 逗号表示 OR,任一匹配即生效 -
media="screen and (hover: hover)"✅ 明确设备类型 + 特性,避免移动端误匹配
漏掉 screen 前缀,在某些 Android WebView 里可能 fallback 到默认行为;用 device-width 而非 width,容易因缩放或 UA 设置导致匹配失败——实际应优先用 CSS 视口宽度(width)。
多个<source>必须从具体到通用排序
浏览器从上到下匹配,命中即停。如果把宽屏规则放在前面,窄屏设备也会被它捕获,后续更精确的规则根本没机会执行。
正确顺序示例:
<picture> <source media="(min-width: 1200px)" srcset="hero-1920.jpg"> <source media="(min-width: 768px)" srcset="hero-1024.jpg"> <source media="(max-width: 767px)" srcset="hero-480.jpg"> <img src="hero-fallback.jpg" alt="Hero"> </picture>
注意三点:
- 没有
media的<source>等价于media="all",应放在最后作为兜底,但不如<img>可靠 -
<img>必须存在,且带src和alt,否则 IE 或旧 WebView 会空白 - 所有
<source>的srcset应指向同构图不同分辨率版本,避免构图突变
动态改media属性不会触发重选
JavaScript 修改 source.media = "(min-width: 400px)" 不会让浏览器立刻重新评估并切换图片。浏览器只在元素首次插入 DOM 或窗口 resize 时检查 media,不监听属性变化。
强行刷新的坑:
- 手动清空
picture.querySelector("img").src = ""再赋新值,会破坏缓存、触发重复请求 - 替换整个
<source>节点可行,但 DOM 操作开销大
更稳妥的做法是用 window.matchMedia() 监听,匹配变化时显式切换 <img> 的 src:
const mql = window.matchMedia("(min-width: 768px)");
mql.addEventListener("change", () => {
const img = document.querySelector("picture img");
img.src = mql.matches ? "desktop.jpg" : "mobile.jpg";
});
真正容易被忽略的是:viewport meta 标签缺失时,(max-width: 480px) 在手机上永远不匹配;<picture> 被设为 display: none 时,Chrome 会暂停所有 <source> 加载——这不是 bug,是规范行为。


















