返回首页

前端图片优化:格式、响应式与懒加载的完整实践

图片往往是页面里最大的资源,也是拖慢 LCP 的头号嫌疑。这篇从选对格式、用 srcset 适配屏幕、懒加载、到防止布局抖动,给一套能直接落地的图片优化清单。

58 约 4 分钟 · 3480 字 前端

打开浏览器的网络面板,你会发现拖慢页面的常常不是 JS,而是图片。一张没处理过的 banner 可能就有两三 MB,而它往往还是首屏最大的元素,直接决定了 LCP(最大内容绘制)这个核心 Web 指标的成绩。

图片优化是性价比最高的前端优化之一。这篇给一套完整的实践清单。

第一步:选对格式

格式选错,后面再怎么优化都是事倍功半。现代格式在同等画质下能小一大截。

格式 特点 适用
AVIF 压缩率最高,支持透明和动画 首选,照片类能比 JPEG 小 50%+
WebP 压缩好,兼容性好 通用首选,AVIF 的稳妥替代
JPEG 有损,无透明 照片(没上现代格式时的兜底)
PNG 无损,支持透明 图标、需要透明的图、线条图
SVG 矢量,任意缩放不失真 图标、Logo、简单插画

实践建议:

  • 照片类:优先 AVIF / WebP,JPEG 兜底。
  • 需要透明:WebP / AVIF / PNG。
  • 图标、Logo:能用 SVG 就用 SVG,矢量、体积小、可无限缩放。
  • 别用 PNG 存照片:无损格式存照片体积会非常大。

用 picture 做格式降级

不是所有浏览器都支持 AVIF。用 <picture> 让浏览器自动挑它支持的第一个格式:

<picture>
  <source srcset="/img/cover.avif" type="image/avif" />
  <source srcset="/img/cover.webp" type="image/webp" />
  <img src="/img/cover.jpg" alt="封面" />
</picture>

浏览器从上往下挑:支持 AVIF 用 AVIF,否则试 WebP,都不支持就用最后的 <img> 里的 JPEG。<img> 是必需的兜底,也是真正承载 alt、尺寸等属性的元素。

第二步:按屏幕提供合适尺寸

给手机用户推一张 2000px 宽的图,是巨大的浪费。用 srcset + sizes 让浏览器按设备挑合适尺寸。

<img
  src="/img/cover-800.jpg"
  srcset="
    /img/cover-400.jpg   400w,
    /img/cover-800.jpg   800w,
    /img/cover-1600.jpg 1600w
  "
  sizes="(max-width: 600px) 100vw, 800px"
  alt="封面"
/>

怎么理解:

  • srcset 里的 400w 是图片的实际像素宽度(不是显示宽度),告诉浏览器有哪些尺寸可选。
  • sizes 告诉浏览器这张图在不同条件下会以多大显示:屏幕 ≤600px 时占满视口(100vw),否则固定 800px
  • 浏览器结合 sizes、设备像素比(DPR)、网络情况,自己挑最合适的那张下载。

这样高分屏拿到高清图,小屏和低 DPR 设备拿到小图,流量和清晰度兼顾。

第三步:懒加载首屏外的图片

首屏之外的图片,没必要一开始就加载。现代浏览器原生支持 loading="lazy":

<img src="/img/photo.jpg" alt="" loading="lazy" />

一个属性搞定,简单可靠,适合绝大多数场景。

首屏的关键图片(尤其 LCP 元素)千万不要加 lazy,反而要让它尽快加载,甚至用 fetchpriority="high" 提高优先级:

<!-- 首屏 banner:高优先级,不要懒加载 -->
<img src="/img/hero.avif" alt="主图" fetchpriority="high" />

需要更精细的控制(占位图、淡入动画、加载统计)时,可以用 IntersectionObserver 自己实现懒加载,但简单场景原生 loading="lazy" 就够了。

第四步:防止布局抖动(CLS)

图片加载完才撑开高度,会把下面的内容"顶"下去,造成布局抖动——这是 CLS(累积布局偏移)变差的主因,体验上就是"页面跳来跳去"。

解决办法:提前告诉浏览器图片的宽高比,让它预留空间。

最简单的是写上 widthheight 属性(即使 CSS 会改变实际显示尺寸,浏览器也会用这两个值算出宽高比预留位置):

<img src="/img/photo.jpg" width="800" height="450" alt="" />

或者用 CSS 的 aspect-ratio:

.cover {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover; /* 裁切填充,不变形 */
}

只要预留了空间,图片加载前后位置就不会跳。

第五步:压缩与控制体积

即使格式选对了,也要压缩。

  • 构建时压缩:用工具链(如 sharp、imagemin、各类打包插件)在构建阶段把图片转成 AVIF/WebP 并压缩,生成多种尺寸。
  • 质量别拉满:照片类 JPEG/WebP 质量设到 75–85 通常肉眼无差,但体积小很多。
  • 图标用 SVG 并优化:用 SVGO 去掉冗余,或做成 SVG sprite / icon font。
  • 控制尺寸上限:别把原图(几千像素)直接挂上去,按实际显示需求生成。

如果用了 Nuxt / Next 这类框架,它们一般自带图片优化模块(如 Nuxt Image),能自动转格式、生成 srcset、按需裁剪,优先用框架能力,别自己造轮子。

第六步:善用 CDN 与缓存

图片是静态资源,应该长缓存。文件名带内容 hash,然后设强缓存:

Cache-Control: public, max-age=31536000, immutable

这样用户二次访问直接命中本地缓存,根本不发请求。再配合 CDN 把图片分发到离用户近的节点,加载更快。很多图片 CDN 还支持 URL 参数实时裁剪、转格式,前端只管按需拼参数即可。

一份落地清单

实际项目里,按这个清单逐项检查:

  1. 照片用 AVIF/WebP,图标用 SVG,别用 PNG 存照片。
  2. <picture> 做格式降级。
  3. srcset + sizes 提供多尺寸,适配不同屏幕和 DPR。
  4. 首屏外图片加 loading="lazy";首屏 LCP 图不要懒加载,可加 fetchpriority="high"
  5. 给每张图写 width/heightaspect-ratio,避免 CLS。
  6. 构建时压缩、生成多尺寸,质量 75–85。
  7. 图片走 CDN + 强缓存(文件名带 hash)。

总结

图片优化没有什么高深技巧,但它实打实地影响 LCP、CLS 这些用户能感知到的指标。核心思路就三条:

  • 更小:选现代格式 + 压缩。
  • 更合适:按屏幕和 DPR 给对应尺寸。
  • 更晚但不影响首屏:首屏外懒加载,首屏图提优先级,并预留空间防抖动。

把上面那份清单走一遍,大多数页面的图片加载体验都能有立竿见影的提升。