srcset 不能用 CSS 变量动态生成,因其在 HTML 解析阶段即被静态读取,此时 CSSOM 未构建、变量不可见;写入 var() 会导致整个 srcset 被忽略而退化为 src 加载。

直接说结论:srcset 不能靠 CSS 变量动态生成,浏览器解析 时 CSS 还没计算、变量也没生效——想用变量控制高清图加载,本质是走不通的路。
为什么 srcset 里不能写 CSS 变量
浏览器在 HTML 解析阶段就处理 srcset,此时样式表尚未加载、:root 里的 --dpr 根本不可见。你写成 srcset="logo.png 1x, logo@2x.png var(--dpr)x",浏览器会直接忽略整个 srcset 属性,退回到只加载 src 的图。
常见错误现象:开发者用 JS 动态设置 document.documentElement.style.setProperty('--dpr', window.devicePixelRatio),再指望 CSS 变量“驱动” srcset ——但 DOM 已渲染完毕,srcset 早已锁定,改变量毫无作用。
-
srcset是 HTML 属性,不是 CSS 声明,不参与 CSSOM 构建 - 所有现代浏览器(Chrome/Firefox/Safari/Edge)都严格按规范,在解析 HTML 时静态读取
srcset字符串 - 试图用
attr()或calc()混入变量,语法直接报错或被静默丢弃
真正能用变量的地方:仅限 background-image + image-set()
如果你非得用 CSS 变量参与高清图逻辑,唯一可行路径是 background-image 配合 image-set(),且变量只能用于兜底 fallback,不能进 image-set() 内部。
正确写法示例:
.hero {
--base-img: "hero-1x.jpg";
--hd-img: "hero-2x.jpg";
background-image: url(var(--base-img));
background-image: image-set(
url(var(--base-img)) 1x,
url(var(--hd-img)) 2x
);
}
注意:
- 上面的
var(--base-img)能生效,是因为它出现在url()函数内,而url()支持 CSS 变量(CSS Values and Units Level 4) - 但
image-set()本身不支持变量插值;1x/2x必须是字面量,不能写成var(--dpr)x - Safari 16.4+、Chrome 110+ 才稳定支持
image-set();旧版 Safari 会跳过整条声明,所以url()兜底必不可少
想动态切换高清图?别绕弯,用 JS 直接换 src 或 srcset
如果业务真需要运行时根据 DPR、网络类型、用户偏好等条件选图,JS 是唯一可靠路径,但必须主动触发重载,且注意避免闪屏。
实操建议:
- 在
DOMContentLoaded后立即判断window.devicePixelRatio,拼出对应srcset字符串 - 对已渲染的
,直接赋值img.srcset = "a-1x.jpg 1x, a-2x.jpg 2x",浏览器会自动发起新请求并替换 - 为防布局抖动,提前设好
width/height或aspect-ratio,确保容器尺寸不变 - 慎用
loading="lazy"+ JS 换图组合:Safari 15.4–16.3 存在竞态 bug,可能加载两次
最易被忽略的细节:即使 srcset 正确加载了 @2x 图,CSS 尺寸仍可能让它变模糊
很多开发者卡在这一步:明明 currentSrc 显示加载的是 logo-200x100@2x.png,但图片还是发虚。
根本原因:CSS 强制设了 width: 100px; height: 50px,而该图物理尺寸是 200×100,DPR=2 时浏览器需缩放 50%,导致插值模糊。
- 优先用
max-width: 100%; height: auto,让图片自然按容器比例缩放 - 若必须固定像素尺寸,请确保
CSS width × devicePixelRatio === 图片原始宽度(例如 DPR=2 时,100px 容器配 200px 图) - 加
image-rendering: -webkit-optimize-contrast或image-rendering: crisp-edges抑制平滑插值(对图标/线稿图有效,对照片慎用)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











