前端图片优化:响应式图片与AVIF格式
把响应式图片和 AVIF 叠在一起用,能把页面图片的传输体积压掉 60%-80%:响应式图片负责「按屏幕选对尺寸」,AVIF 负责「把每个尺寸压到最小」。落地路径就是 <picture> 里按 AVIF → WebP → JPEG 的顺序放 <source>,再在 <img> 上用 srcset + sizes 给出多档宽度。
响应式图片和 AVIF 分别解决什么问题?
结论:srcset/sizes 解决的是「尺寸浪费」,AVIF 解决的是「编码效率」,两者互不替代、必须同时上。
一张 1920px 宽的 JPEG 显示在 375px 宽的手机上,浏览器要下载的像素是实际显示的 5 倍,浪费 80% 的带宽。srcset 让浏览器自己挑一档合适的宽度,这是尺寸维度的优化。
AVIF 是 2019 年定稿的图片格式,底层用 AV1 视频编码的帧内编码。结论:在相同主观画质下,AVIF 比 JPEG 小 50% 左右,比 WebP 小 20%-30%。一张 1920×1080 的 JPEG(q80)体积 320KB,转成 AVIF(q55)是 110KB,降幅 65%;转成 WebP(q75)是 180KB,降幅 44%。
尺寸维度砍 80%,格式维度再砍 65%,两者相乘才是那 60%-80% 的总体降幅。
img 的 srcset 和 sizes 到底怎么写?
结论:w 描述符必须配 sizes,不写 sizes 浏览器按 100vw 估算,等于白做。
<img
src="hero-1200.jpg"
srcset="hero-480.jpg 480w, hero-800.jpg 800w,
hero-1200.jpg 1200w, hero-1920.jpg 1920w"
sizes="(max-width: 640px) 100vw,
(max-width: 1200px) 50vw,
640px"
width="1600" height="900"
decoding="async"
fetchpriority="high"
alt="产品主图">
四个要点:
- 宽度档位取 480 / 800 / 1200 / 1920,覆盖 1x 与 2x 屏;
sizes是给浏览器的「布局提示」,写的是图片在视口里占多宽,不是图片文件宽度;width/height必须写,否则会产生 CLS(布局偏移);- LCP 图片不要加
loading="lazy",反而要加fetchpriority="high",懒加载会把 LCP 推迟几百毫秒。
picture 和 AVIF 的降级顺序怎么写?
结论:<source> 按 AVIF → WebP → JPEG 从新到旧排列,浏览器取第一个认识的,后面的全部忽略。
<picture>
<source type="image/avif"
srcset="hero-480.avif 480w, hero-800.avif 800w, hero-1920.avif 1920w"
sizes="(max-width: 640px) 100vw, 640px">
<source type="image/webp"
srcset="hero-480.webp 480w, hero-800.webp 800w, hero-1920.webp 1920w"
sizes="(max-width: 640px) 100vw, 640px">
<img src="hero-1200.jpg" width="1600" height="900" alt="产品主图">
</picture>
type 属性是关键:浏览器不解析不支持的格式,所以不会产生额外请求。<img> 的 src 是最终兜底,永远保留 JPEG,不要为了省事删掉。
AVIF 兼容性够用吗?有什么代价?
结论:主流浏览器全部支持,可以直接作为首选格式;代价是编码慢和解码耗电。
时间线:Chrome / Edge 85(2020 年 8 月)、Firefox 93(2021 年 10 月)、Safari 16(2022 年 9 月)起支持 AVIF。至此四大内核全部具备解码能力,所以不需要做 UA 嗅探,交给 <picture> 的 type 协商即可。
代价有两块:
- 编码慢:AVIF 的编码耗时是 WebP 的 5-10 倍。结论:必须在构建期或上传期一次性生成,不能放在运行时实时转码。
- 解码贵:低端手机上 AVIF 解码比 JPEG 多耗电,且 AVIF 没有渐进式渲染,大图会「先白屏、再整张出现」。首屏主图保持 JPEG 兜底更稳。
AVIF 参数怎么调?
结论:AVIF 的 quality 取 50-60,等效于 JPEG 的 quality 75-80,effort 取 4 平衡速度与体积。
用 sharp:
sharp('in.jpg').avif({ quality: 55, effort: 4 }).toFile('out.avif');
用 avifenc:
avifenc -q 60 -s 4 -j all in.png out.avif
effort 取 0-9,越高压缩率越好、耗时越长,构建期用 4,离线批处理可以拉到 6。默认 4:2:0 色度抽样对照片没问题,但图标、Logo、带细文字的截图不要用 AVIF 有损压缩,边缘会出现色块,这类素材用 PNG 或 WebP 无损。
三个最容易踩的坑
结论:sizes 写错、LCP 图懒加载、无脑全量转 AVIF,这三个问题的破坏力比收益大。
sizes不写或写成固定像素,浏览器按100vw拉图,手机上也可能下载 1920w 的文件。- LCP 图加了
loading="lazy",或者没写width/height,LCP 和 CLS 两个指标同时恶化。 - 只转 AVIF 不留 JPEG,遇到老设备或图片代理会整张图裂开。
另外,构建工具可以直接省掉手写标签:Next.js 在 next.config.js 里配 images.formats: ['image/avif', 'image/webp'],Vite 用 vite-imagetools,Astro 用 astro:assets,都会自动产出 srcset。
总结一下:<picture> 管格式协商,srcset + sizes 管尺寸选择,AVIF 管压缩率,三者组合是当前前端图片优化的默认答案;同时记住保留 JPEG 兜底、LCP 图不懒加载、AVIF 只在构建期生成这三条底线。
原文链接:https://www.gj0.com/thread-551.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。