HTML 中,img 标签 srcset 属性的作用是什么?

www.jswusn.com HTML 2026-05-28 10:08:28 4次浏览

手机上打开页面,第一屏图片加载了 2.8MB。

我第一眼就不太信业务代码有多复杂,先开 DevTools,看 Network,果然一张商品图在 390px 宽的屏幕上,请求的是 2400px 的大图。页面慢,不是接口慢,也不是 JS 执行慢,就是图片喂太狠了。

这时候就该看 imgsrcset

srcset 不是给图片加备用地址那么简单。它的作用是:把同一张图的多个规格告诉浏览器,让浏览器自己根据屏幕宽度、设备像素比、sizes 规则去挑一张最合适的图。

别小看“浏览器自己挑”这几个字。图片这块你用 JS 硬算,八成越写越别扭,还容易算错。

最常见的写法长这样:

<img
  src="/img/goods-800.jpg"
  srcset="
    /img/goods-400.jpg 400w,
    /img/goods-800.jpg 800w,
    /img/goods-1200.jpg 1200w
  "
  sizes="(max-width: 600px) 92vw, 520px"
  alt="商品主图"
/>

这里别急着背属性,直接看浏览器怎么判断。

如果屏幕宽度小于 600px,这张图在页面里大概占 92vw,也就是视口宽度的 92%。

假设手机视口是 390px,那么图片展示宽度大概是:

const viewport = 390;
const displayWidth = viewport * 0.92;

console.log(displayWidth); // 358.8

但浏览器不会只看 CSS 宽度,还会看设备像素比。

比如 iPhone 上 devicePixelRatio 可能是 3,那它真正希望拿到的图片资源宽度大概是:

const cssWidth = 390 * 0.92;
const dpr = 3;

const expectImageWidth = Math.ceil(cssWidth * dpr);

console.log(expectImageWidth); // 1077

这时候候选图里有 400、800、1200。

浏览器大概率会选 1200w,因为 800w 在高 DPR 屏幕上可能会糊,1200w 更接近需要的清晰度。

这就是 srcset 干的事。

不是你写一堆判断:

const img = document.querySelector('#goods-cover');
const width = window.innerWidth;
const dpr = window.devicePixelRatio || 1;

if (width * dpr <= 400) {
  img.src = '/img/goods-400.jpg';
} else if (width * dpr <= 800) {
  img.src = '/img/goods-800.jpg';
} else {
  img.src = '/img/goods-1200.jpg';
}

这种代码我一般不爱放线上。

不是不能用,是它管得太多。屏幕旋转怎么办?布局变化怎么办?图片不是满屏而是卡片里 180px 宽怎么办?用户浏览器已经有选择算法了,你非要自己接管,后面维护的人会骂。

更靠谱的是让 HTML 把规则说清楚:

<img
  src="/img/article-cover-800.jpg"
  srcset="
    /img/article-cover-360.jpg 360w,
    /img/article-cover-720.jpg 720w,
    /img/article-cover-1080.jpg 1080w
  "
  sizes="
    (max-width: 480px) 94vw,
    (max-width: 900px) 70vw,
    640px
  "
  alt="文章封面"
/>

这段里我最关心的不是 srcset,而是 sizes

因为 srcset 只是告诉浏览器“我手里有哪些图”。sizes 才是告诉浏览器“这张图最终大概要显示多宽”。

如果你只写 srcset,不写 sizes,浏览器会按默认的 100vw 去估算。这个坑挺常见。

比如图片实际在右侧卡片里,只有 300px 宽,但你没写 sizes,浏览器以为它要占满整屏,可能就选了一张更大的图。

看着没报错,Network 里全是浪费。

还有一种写法是按像素倍率写:

<img
  src="/img/avatar@1x.png"
  srcset="
    /img/avatar@1x.png 1x,
    /img/avatar@2x.png 2x,
    /img/avatar@3x.png 3x
  "
  width="80"
  height="80"
  alt="用户头像"
/>

这个适合头像、图标、小尺寸固定图片。

比如头像永远就是 80px,不随屏幕变来变去,那就没必要写 400w、800w 这种宽度描述,直接告诉浏览器:普通屏用 1x,高清屏用 2x 或 3x。

这里也别贪。

头像 80px,你上来塞一张 2000px 的原图,然后指望浏览器自己压缩显示,页面是能显示,但流量和解码成本都吃亏。

我一般会用一段小脚本扫一下页面上的图片,先把离谱的找出来:

const badImages = [...document.images]
  .map((img) => {
    const box = img.getBoundingClientRect();

    return {
      src: img.currentSrc || img.src,
      showWidth: Math.round(box.width),
      realWidth: img.naturalWidth,
      wasteRatio: img.naturalWidth && box.width
        ? Number((img.naturalWidth / box.width).toFixed(2))
        : 0
    };
  })
  .filter(item => item.wasteRatio > 3);

console.table(badImages);

这个脚本不是生产代码,就是排查用。

重点看 currentSrc。用了 srcset 以后,img.src 不一定能说明浏览器最后选了哪张图,currentSrc 才更接近现场。

比如你看到日志是这样:

{
  src: "https://static.xxx.com/goods-1200.jpg",
  showWidth: 360,
  realWidth: 1200,
  wasteRatio: 3.33
}

这就要回去看两个地方。

一个是候选图是不是缺了中间规格。 一个是 sizes 写得是不是太大。

比如这个就不太对:

<img
  src="/img/goods-800.jpg"
  srcset="
    /img/goods-800.jpg 800w,
    /img/goods-1600.jpg 1600w
  "
  sizes="100vw"
  alt="商品图"
/>

移动端卡片图实际只有半屏宽,你写 100vw,浏览器不选大图才怪。

改成更贴近布局的:

<img
  src="/img/goods-800.jpg"
  srcset="
    /img/goods-360.jpg 360w,
    /img/goods-720.jpg 720w,
    /img/goods-1080.jpg 1080w
  "
  sizes="
    (max-width: 600px) 46vw,
    280px
  "
  alt="商品图"
/>

这才像是在跟真实页面对齐。

srcset 还有一个容易误会的点:它不是懒加载。

懒加载是控制什么时候加载:

<img
  loading="lazy"
  src="/img/list-720.jpg"
  srcset="
    /img/list-360.jpg 360w,
    /img/list-720.jpg 720w
  "
  sizes="(max-width: 600px) 48vw, 260px"
  alt="列表图片"
/>

srcset 是控制加载哪一张。

这两个可以一起用,但别混成一个概念。线上排性能问题时,这两个方向也要分开看。首屏慢,先看首屏图是不是太大;长列表滚动卡,再看懒加载和图片解码。

还有兜底问题。

src 不能省。老浏览器、爬虫、某些特殊环境不一定完整支持 srcsetsrc 至少能保证图片还能显示。

<img
  src="/img/banner-960.jpg"
  srcset="
    /img/banner-480.jpg 480w,
    /img/banner-960.jpg 960w,
    /img/banner-1440.jpg 1440w
  "
  sizes="100vw"
  alt="活动 Banner"
/>

这段里,src="/img/banner-960.jpg" 就是兜底资源。

真要验证 srcset 有没有生效,不要只看页面肉眼清不清晰。肉眼不靠谱,尤其是设计图本来就糊的时候。

直接看浏览器最终选了谁:

document.querySelectorAll('img').forEach((img) => {
  img.addEventListener('load', () => {
    console.log('[img-loaded]', {
      alt: img.alt,
      currentSrc: img.currentSrc,
      naturalWidth: img.naturalWidth,
      clientWidth: Math.round(img.getBoundingClientRect().width),
      dpr: window.devicePixelRatio
    });
  });
});


这段加到本地调试环境里,刷新页面,多切几个设备尺寸,基本就能看出问题。

srcset 的价值不在于写法多高级,而在于把图片选择这件事从 JS 和后端模板里拿出来,交给浏览器按真实环境处理。

屏幕宽度、DPR、布局宽度、缓存状态、网络条件,这些东西浏览器比我们更接近现场。

你给它足够准确的候选图和 sizes,它通常会选得比手写判断稳。

图片性能问题很多时候不吵不闹,接口 80ms,JS 也没报错,页面就是慢。最后一查,是移动端加载了桌面大图。

这种问题,srcset 能挡掉不少。


上一篇:没有了!

HTML

下一篇:让你大跌眼镜的疯狂 HTML 和 CSS 技巧

技术分享

苏南名片

  • 联系人:吴经理
  • 电话:152-1887-1916
  • 邮箱:message@jswusn.com
  • 地址:江苏省苏州市相城区

热门文章

Copyright © 2018-2026 jswusn.com 版权所有

技术支持:苏州网站建设  苏ICP备18036849号