跳到主要内容

图片优化与自适应策略

1. 格式选择

格式压缩透明动画浏览器支持适合
AVIF最优(比 WebP 小 20-30%)Chrome 85+, Firefox 93+首选
WebP优(比 JPEG 小 25-35%)全主流通用
JPEG全部fallback
PNG无损全部图标/截图
SVG矢量全部图标/logo

决策:AVIF > WebP > JPEG。用 <picture> 渐进增强。

2. <picture> 渐进增强

<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="Hero" width="1200" height="600"
loading="lazy" decoding="async">
</picture>

浏览器按顺序选第一个支持的格式。

3. 响应式图片(srcset + sizes)

<img
srcset="
hero-400.webp 400w,
hero-800.webp 800w,
hero-1200.webp 1200w,
hero-1600.webp 1600w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
src="hero-800.webp"
alt="Hero"
width="1200"
height="600"
loading="lazy"
decoding="async"
/>

浏览器根据 viewport + 设备像素比选合适尺寸。

sizes 含义:

  • 视口 ≤ 600px → 图片占满宽度(100vw)
  • 视口 ≤ 1200px → 图片占一半(50vw)
  • 更大 → 固定 800px

4. 懒加载

<!-- 首屏图不要 lazy(影响 LCP) -->
<img src="hero.webp" fetchpriority="high" alt="Hero">

<!-- 非首屏图 -->
<img src="thumb.webp" loading="lazy" decoding="async" alt="...">

loading="lazy" 原生支持。交叉观察器(IntersectionObserver)更灵活但一般不需要。

4.1 首屏 LCP 图片优化

<!-- preload + fetchpriority -->
<link rel="preload" as="image" href="hero.avif" type="image/avif"
imagesrcset="hero-400.avif 400w, hero-800.avif 800w"
imagesizes="100vw">

<img src="hero.avif" fetchpriority="high" alt="Hero"
width="1200" height="600">

LCP 图片不要懒加载 + preload + fetchpriority="high"。

5. CDN 图片处理

各 CDN 支持 URL 参数实时处理:

5.1 阿里云 OSS

https://bucket.oss-cn-hangzhou.aliyuncs.com/photo.jpg?x-oss-process=image/resize,w_800/format,webp/quality,Q_80

5.2 Cloudflare Images

https://example.com/cdn-cgi/image/width=800,format=auto,quality=80/photo.jpg

format=auto 根据 Accept 头自动选 AVIF / WebP / JPEG。

5.3 Imgix / Cloudinary

https://myapp.imgix.net/photo.jpg?w=800&auto=format&q=80

6. 构建时优化

6.1 sharp(Node)

npm i sharp
const sharp = require('sharp')

// 批量转 WebP + AVIF
await sharp('input.jpg')
.resize(800)
.webp({ quality: 80 })
.toFile('output.webp')

await sharp('input.jpg')
.resize(800)
.avif({ quality: 60 })
.toFile('output.avif')

6.2 Vite 插件

// vite.config.ts
import { viteImagemin } from 'vite-plugin-imagemin'

export default {
plugins: [
viteImagemin({
gifsicle: { optimizationLevel: 3 },
mozjpeg: { quality: 80 },
pngquant: { quality: [0.7, 0.9] },
webp: { quality: 80 },
avif: { quality: 60 },
})
]
}

6.3 Next.js Image

import Image from 'next/image'

<Image
src="/hero.jpg"
width={1200}
height={600}
alt="Hero"
priority // 首屏
placeholder="blur" // 模糊占位
blurDataURL="data:image/..."
/>

Next.js Image 自动:

  • 按设备 srcset
  • WebP / AVIF 自动协商
  • 懒加载(非 priority)
  • 防 CLS(必填 width/height)

7. 占位策略

防 CLS + 提升感知速度:

7.1 固定宽高

<img width="800" height="600" src="..." alt="...">

CSS aspect-ratio 等效:

img { aspect-ratio: 4/3; width: 100%; height: auto; }

7.2 LQIP(低质量占位)

构建时生成 10px 缩略图 base64:

<img src="full.webp" style="background: url(data:image/jpeg;base64,...) no-repeat center/cover">

7.3 BlurHash

import { encode } from 'blurhash'
// 编码为 4x3 的 hash 字符串
const hash = encode(imageData, 4, 3)
// 前端 decode 渲染 canvas

更小的占位表示。

7.4 CSS dominant color

<div style="background-color: #3a7bd5; aspect-ratio: 16/9;">
<img loading="lazy" src="..." alt="...">
</div>

8. SVG 优化

# SVGO 压缩
npx svgo input.svg -o output.svg

# 批量
npx svgo -f ./src/icons/ -o ./dist/icons/
// svgo.config.js
module.exports = {
plugins: [
'preset-default',
{ name: 'removeViewBox', active: false },
'removeDimensions',
]
}

9. 视频替代 GIF

GIF 体积巨大。用 &lt;video> 替代:

<video autoplay loop muted playsinline>
<source src="animation.webm" type="video/webm">
<source src="animation.mp4" type="video/mp4">
</video>

WebM 通常比等效 GIF 小 80%+。

10. 性能预算

{
"size-limit": [
{ "path": "dist/images/**/*.{jpg,png,webp}", "limit": "500 KB" }
]
}

单页总图片传输 < 1MB(移动端)。

11. 监控

// 慢图片上报
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.initiatorType === 'img' && entry.duration > 2000) {
reportSlowImage({
url: entry.name,
size: entry.transferSize,
duration: entry.duration,
})
}
}
}).observe({ type: 'resource', buffered: true })

12. 常见反模式

  • 首屏 LCP 图 lazy load:LCP 变慢
  • 不设 width/height:CLS
  • 2000px 图给 400px 容器:浪费带宽
  • 不用 WebP / AVIF:多 30-50% 体积
  • PNG 存照片:应该 JPEG/WebP
  • GIF 动图:用 video 代替
  • 图片不走 CDN:回源慢
  • 不限最大尺寸:用户上传 10MB 原图
  • 所有图 fetchpriority="high":等于没标
  • SVG 不压缩:可能含几十 KB 无用 metadata

13. 延伸阅读