← 返回博客

如何优化网站图片加载速度:从20秒到1秒的实战经验

2026年5月6日 · 阅读约12分钟

作为一个自己搭建和维护多个网站的开发者,图片加载速度是我花最多时间优化的问题之一。 本文不是理论性的最佳实践清单,而是我在真实项目中踩过坑、反复测试后总结出的实战经验—— 包括哪些优化真正有效、哪些看似有用实则浪费精力,以及具体的实施步骤。

为什么图片优化如此重要

根据 HTTP Archive 的数据,2025年网页平均加载的数据量中,图片占比约为 65-75%。 换句话说,你网站的加载速度很大程度上取决于图片处理是否得当。

用户的行为数据更能说明问题:

我的优化前后对比

以一个我维护的个人摄影博客为例,首页展示 24 张缩略图,每张原始图片约 2-3MB:

阶段总图片体积首屏加载时间LCP
优化前(原始JPG)约 58MB18-25秒12.4秒
仅压缩图片约 8MB3-5秒2.8秒
+ 懒加载 + WebP约 2.5MB(首屏)0.8-1.2秒0.9秒
+ CDN + 响应式约 1.2MB(首屏)0.4-0.6秒0.5秒

注意这个数字是在 4G 网络下的测试结果,不是实验室的千兆网络。 在 WiFi 环境下,优化后的加载时间可以降到 0.2 秒以内。

优化方案一:图片压缩(收益最大)

如果你只能做一件事,那就是压缩图片。这是性价比最高的优化, 不需要改代码、不需要改架构,只需要处理好素材即可。

压缩策略

我的实际压缩脚本(Node.js + Sharp)

const sharp = require('sharp');
const fs = require('fs');

async function optimizeImage(inputPath, outputDir) {
  const filename = path.basename(inputPath, path.extname(inputPath));
  
  // 生成响应式图片集
  const sizes = [
    { width: 400, suffix: 'thumb' },
    { width: 800, suffix: 'medium' },
    { width: 1200, suffix: 'large' }
  ];
  
  for (const size of sizes) {
    // WebP 版本
    await sharp(inputPath)
      .resize(size.width, null, { withoutEnlargement: true })
      .webp({ quality: 80 })
      .toFile(`${outputDir}/${filename}-${size.suffix}.webp`);
    
    // JPG 后备版本
    await sharp(inputPath)
      .resize(size.width, null, { withoutEnlargement: true })
      .jpeg({ quality: 85, progressive: true })
      .toFile(`${outputDir}/${filename}-${size.suffix}.jpg`);
  }
}

优化方案二:现代图片格式(WebP / AVIF)

WebP 的支持率已经超过 95%,AVIF 在 Chrome 和 Firefox 中也都支持了。 我的建议是:

实际代码示例

<picture>
  <source
    srcset="/images/photo-large.avif"
    type="image/avif"
    media="(min-width: 800px)"
  />
  <source
    srcset="/images/photo-large.webp"
    type="image/webp"
    media="(min-width: 800px)"
  />
  <source
    srcset="/images/photo-thumb.webp"
    type="image/webp"
  />
  <img
    src="/images/photo-thumb.jpg"
    alt="描述"
    loading="lazy"
    width="400"
    height="300"
  />
</picture>

关键点:浏览器会从上到下依次检查,使用第一个它支持的格式。 提供明确的 width/height 属性避免布局偏移(CLS),这也是 Core Web Vitals 的评分因素。

优化方案三:懒加载(Lazy Loading)

懒加载的原理很简单:页面初次加载时,只加载用户视野内(viewport)的图片, 其他图片等用户滚动到附近时再加载。

现代浏览器已经原生支持懒加载,只需要在 img 标签上添加 loading="lazy" 属性即可:

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

但原生懒加载有几个需要注意的地方:

优化方案四:响应式图片

不要在手机上加载 1920px 宽的大图。使用 srcset 让浏览器根据设备屏幕宽度自动选择合适尺寸的图片:

<img
  srcset="
    image-400.webp 400w,
    image-800.webp 800w,
    image-1200.webp 1200w
  "
  sizes="
    (max-width: 600px) 100vw,
    (max-width: 1200px) 50vw,
    33vw
  "
  src="image-800.webp"
  alt="..."
/>

sizes 属性告诉浏览器"这张图片在不同屏幕宽度下大概会占多少视口宽度", 浏览器据此计算需要的像素数,从 srcset 中选择最合适的图片。这样可以确保:

我的经验是:为每个图片准备 3-4 个尺寸版本就够了(如 400w、800w、1200w), 太多版本会增加构建复杂度,收益递减。

优化方案五:CDN 与 HTTP/2

如果上述优化都做了,加载速度还是慢,问题可能出在网络传输上。 特别是对于全球用户访问的网站,CDN 的作用非常显著。

CDN 选择建议

HTTP/2 和 HTTP/3

现代 CDN 和云服务商基本都默认支持 HTTP/2。HTTP/2 的多路复用特性可以并行加载多张图片, 不需要像 HTTP/1.1 那样做域名分片(domain sharding)。HTTP/3 基于 QUIC 协议, 在网络不稳定的环境下(如移动网络)表现更好。如果你的 CDN 支持 HTTP/3,建议开启。

优化方案六:缓存策略

图片是静态资源,非常适合长期缓存。合理的缓存策略可以让重复访问的用户几乎不需要重新下载图片:

# Nginx 配置示例
location ~* \.(jpg|jpeg|png|webp|avif)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Vary "Accept";
}

关键点:

文件变更怎么办?用文件名哈希(如 photo.a3f8b2.jpg), 每次修改生成新文件名,旧文件继续缓存。Next.js 和 Vite 等构建工具会自动处理这个。

不值得投入的优化(避免过度优化)

有些优化在网上被大量推荐,但实际收益很小,或者维护成本很高:

实施顺序建议

如果你现在就想开始优化,按这个顺序执行,每一步都有明确的收益:

  1. 压缩现有图片 + 转 WebP(当天见效)
    用 Squoosh 或脚本批量处理,这是收益最大的单一步骤
  2. 添加懒加载(30分钟)
    给非首屏图片加 loading="lazy",使用原生 API 不需要任何库
  3. 实现响应式图片(1-2小时)
    为图片生成 2-3 个尺寸版本,使用 srcset + sizes
  4. 配置 CDN(1小时)
    Cloudflare 免费版开通即用,收益显著
  5. 优化缓存头(30分钟)
    给图片加长期缓存,配合文件名哈希策略
  6. 考虑 AVIF(后续迭代)
    在 WebP 基础上,为重要图片额外生成 AVIF 版本

测试和监控

优化后一定要用工具验证效果:

我的习惯是:每次重大改动后跑一遍 Lighthouse,记录分数变化趋势。 不要追求 100 分,对于内容型网站,90 分以上就已经非常好了。

总结

网站图片优化的核心思路是:

不需要一次做完所有优化,根据实际瓶颈逐个解决。 用 Chrome DevTools 的 Network 面板分析自己网站的实际加载情况, 找到最大的瓶颈优先处理,通常能获得 80% 的收益。

处理图片时还有水印需要清理?

免费去水印 →