HTML 响应式图片完整教程:srcset / sizes / picture 标签

pantao
pantao 正式会员正式会员认证极客认证极客
发布于 2026-10-08 11:59 ·4 浏览 ·0 回复

学完这篇,你能把一个 <img> 标签从「一张大图硬撑所有屏幕」改成「浏览器自己挑最合适的尺寸下载」,手机用户不再白下 2MB 的桌面大图。

先说清楚一件事:响应式图片解决的不是「显示大小」问题——那个用 CSS 的 max-width: 100% 就够了。它解决的是带宽和清晰度问题:让手机下 480px 的图,让 4K 屏下 1920px 的图,同一段 HTML 全自动完成。

第一步:先把一张图导出成多个尺寸

这一步没有代码,但躲不掉。用 Photoshop、Squoosh、ImageMagick 或构建工具都行,导出一组宽度递进的图:

hero-480.jpg    480 × 320
hero-960.jpg    960 × 640
hero-1440.jpg  1440 × 960
hero-1920.jpg  1920 × 1280

注意:尺寸要按「实际会渲染的最大宽度」定,别盲目铺 320/640/960/1280/1600/1920 六档。一般 4~5 档足够,档位太多反而让浏览器挑花眼、缓存命中率下降。

第二步:用 srcset 写出候选清单(w 描述符)

w 描述符填的是这张图本身的像素宽度,不是你希望它显示多宽——这是新手最容易搞反的地方。

<img
  src="hero-960.jpg"
  srcset="hero-480.jpg 480w,
          hero-960.jpg 960w,
          hero-1440.jpg 1440w,
          hero-1920.jpg 1920w"
  alt="示例配图">

注意:src 属性必须保留。它是老浏览器、部分 RSS 阅读器和邮件客户端的兜底,也常常是搜索引擎抓取的入口。srcset 是增强,不是替代。

第三步:用 sizes 告诉浏览器「到底显示多宽」

只写 srcset 不写 sizes,浏览器默认按 100vw(整个视口宽)来估算,于是在 1440px 的桌面屏幕上,哪怕你的正文栏只有 700px,它也可能去下 1440w 的图。

sizes 就是用来纠正这个假设的:

<img
  src="hero-960.jpg"
  srcset="hero-480.jpg 480w,
          hero-960.jpg 960w,
          hero-1440.jpg 1440w,
          hero-1920.jpg 1920w"
  sizes="(max-width: 600px) 100vw,
         (max-width: 1200px) 50vw,
         700px"
  alt="示例配图">

读法:从前往后,第一条命中的媒体条件生效;最后一条不带条件的作为兜底。手机(≤600px)图片占满屏宽,平板占一半,桌面固定 700px。

浏览器拿到后的计算逻辑是:sizes 算出的显示宽度 × 设备像素比(DPR)= 需要的像素宽度,然后挑「大于等于这个值里最小的那张」。比如桌面 700px 显示宽度、DPR=2,需要 1400px,浏览器就会选 1440w 那张。

注意:sizes 里的断点要和 CSS 里真正改变布局的断点对上。如果你在 CSS 里 768px 处变成两栏,sizes 里却写 600px,浏览器就会算错宽度、下错图。另外别忘了容器自身的 padding 和 margin——sizes 描述的是图片的渲染宽度,不是容器宽度。

第四步:尺寸固定的图,用 x 描述符更省事

如果一张图永远显示 80×80(比如用户头像),不需要 sizes,直接用 DPR 描述符:

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

注意:同一个 srcset 里绝对不能混用 w 和 x,一旦混用,浏览器会直接忽略整个 srcset,静默退回 src。这个错误不报错、不提示,只能靠自己检查。

第五步:picture —— 需要「换图」而不只是「换大小」时

srcset 只能缩放同一张图,<picture> 才能真正换内容。两种典型场景:

场景 A:艺术指导(不同屏幕裁不同的构图)

<picture>
  <source media="(max-width: 600px)" srcset="hero-sq-600.jpg">
  <source media="(max-width: 1200px)" srcset="hero-wide-1200.jpg">
  <img src="hero-1920.jpg" alt="示例配图" width="1920" height="800">
</picture>

手机上用正方形裁切,桌面用宽幅横图,各取所需。

场景 B:格式降级(AVIF → WebP → JPEG)

<picture>
  <source type="image/avif"
          srcset="hero-960.avif 960w, hero-1920.avif 1920w"
          sizes="(max-width: 600px) 100vw, 700px">
  <source type="image/webp"
          srcset="hero-960.webp 960w, hero-1920.webp 1920w"
          sizes="(max-width: 600px) 100vw, 700px">
  <img src="hero-960.jpg"
       srcset="hero-960.jpg 960w, hero-1920.jpg 1920w"
       sizes="(max-width: 600px) 100vw, 700px"
       alt="示例配图" width="1920" height="1280">
</picture>

浏览器从上往下判断,支持 AVIF 就用 AVIF,否则试 WebP,都不行就用 <img> 里的 JPEG。

注意三点:① <source> 上也要写 sizes,它不会从 <img> 继承;② <img> 是 <picture> 里唯一必需的元素,alt 只能写在它上面,写在 <source> 上是无效的;③ media 条件同样是从上往下第一条命中即用,别把宽条件写在窄条件前面。

第六步:补齐宽高、懒加载和首屏优先级

<img src="hero-960.jpg"
     srcset="..."
     sizes="..."
     width="1920" height="1280"
     loading="lazy" decoding="async"
     alt="示例配图">

CSS 里保持:

img { max-width: 100%; height: auto; }

width/height 配合 height: auto 能让浏览器提前算出宽高比占好位,避免图片加载时页面跳动(CLS 指标)。

注意:loading="lazy" 不要加在首屏大图(LCP 元素)上,那会拖慢首屏;首屏图反而应该加 fetchpriority="high",并把 src 指向中等尺寸那档。

小结

  • srcset + w 描述符 = 候选图片清单,sizes = 浏览器估算显示宽度的依据,两者必须成对出现才有意义。
  • 固定尺寸的图用 x 描述符,不要写 sizes;w 和 x 严禁混用。
  • 需要换构图或换格式时用 <picture>,<source> 上要重写 sizes,<img> 必须保留并携带 alt。
  • sizes 里的断点必须和 CSS 布局断点一致,否则浏览器会算错、下错图。
  • 永远保留 src 作为兜底;给首屏图加 fetchpriority="high",给非首屏图加 loading="lazy",并写全 width/height 防止布局抖动。
  • 上线后用 DevTools 的 Network 面板把窗口拖到几个断点,确认每次真的只下了一张、且是你预期的那张。
本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-750.html
转载请注明出处,版权归原作者所有。

全部回复 0

还没有回复,来抢沙发~