一句话说清楚
压网站图片却不掉画质的关键,不是一上来就把质量滑块拉到“还能忍”的最低值。真正的起点,是这张图在页面里到底做什么用。首屏 Hero、可放大的商品图、博客配图、头像、界面截图和背景纹理,各自需要不同的尺寸、格式和质量。
一条好用的规则是:先缩到实际展示的最大尺寸,然后在“在布局里看不出变化”的范围内适度压缩。 一张博客图在页面上宽 760 CSS 像素显示,高密度屏幕下 1500–1600 px 的源图通常就够了。5000 px 的相机原图就是浪费数据;反过来,直接导出 760 px 又会在 Retina 上偏软。合适的文件在两个极端之间。
“不损失画质”也需要一个务实的定义。放到网页语境里,通常指的是在访客真正看到的尺寸下没有可见的画质损失,而不是数学意义上的像素级完全一致。压缩后的 WebP 与原文件并不相同,但在页面里可以做到视觉上无法区分。
先判断这张图属于哪一类
在选 WebP、AVIF、JPEG、PNG 或一个质量数值之前,先把这张图归类:
| 图片角色 | 常见展示尺寸 | 起手格式 | 起手质量 | 需要重点看的地方 |
|---|---|---|---|---|
| LCP 首屏 Hero | 宽 1200–2400 px | AVIF + WebP/JPEG 兜底 | AVIF 45–65,WebP 78–85 | 天空、皮肤、阴影、品牌色 |
| 博客/正文配图 | 源图宽 1200–1600 px | WebP,JPEG 兜底 | WebP 78–85 | 细节与渐变 |
| 商品列表缩略图 | 源图宽 500–900 px | WebP | WebP 70–78 | 文字标签、边缘、纹理 |
| 商品详情图 | 源图宽 1200–2000 px | WebP 或 AVIF | WebP 82–88,AVIF 50–70 | 放大后的细节与色彩还原 |
| UI 截图 | 实际显示尺寸或 2x | PNG 或无损 WebP | 涉及文字用无损 | 文字、图标、锐边 |
| Logo 或图标 | 尽量用矢量 | SVG | 不适用 | 缩放不糊 |
| 背景纹理 | 只按展示尺寸出 | WebP 或 JPEG | 60–75 | 色带与拼缝 |
这张表故意带态度。网站图片压得差,大多数情况就是把所有素材当同一件事处理。首页 Hero 会影响 Largest Contentful Paint;商品详情图会影响信任和转化;装饰性背景没人细看,可以做得轻很多。
先缩放:尺寸做了大部分工作
压缩降低的是“存这张固定像素网格”所占的字节;缩放改变的是像素网格本身。当源图的像素远多于页面能显示的量,缩放才是最干净的省法。
一条简单的定尺公式:
目标源图宽度 = 最大 CSS 显示宽度 × 设备像素比
举几个例子:
- 卡片图以 320 CSS px 展示,2x 屏幕对应 640 px 源图。
- 博客图以 760 CSS px 展示,源图 1500–1600 px。
- 接近 1200 CSS px 的整宽 Hero,视裁切和受众设备可能需要 2000–2400 px 源图。
不要机械地给每张图都用 3x。web.dev 提到,DPR 和布局是一起起作用的;在很多情况下,用户根本感知不到超高 DPR 图源带来的收益。2400 px 的 Hero 可能合理;“像素多总没错”的 5000 px Hero,大多只是在烧带宽。
PhotoTools 把这两件事分开:需要精确像素或缩短长边时用 Resize,然后在 Compress 里挑 JPEG、WebP 或 AVIF,微调质量。
动质量之前先选格式
格式决定了“哪种细节可以被干净地去掉”。
- 多数网页照片用 WebP。 现代浏览器广泛支持,视觉画质相近时通常比 JPEG 更小。Google 的 WebP 文档给出的对比数据是:相较同质量 JPEG 有 25–34% 的体积节省。
- 对字节斤斤计较时用 AVIF。 AVIF 在大幅照片素材上可以压过 WebP,但编码更慢,也会让交付链更复杂。要搭配兜底格式使用,不要作为唯一输出。
- JPEG 用作兼容兜底。 邮件、老 CMS 流程、下载分发以及
<img>的兜底源,JPEG 还是有用武之地。 - 截图和文字类内容用 PNG 或无损 WebP。 有损的 JPEG/WebP 会让 UI 小字发糊,也会在锐边周围出色噪。
- Logo 与图标用 SVG。 位图 Logo 转 WebP 或许比 PNG 更小,但一个干净的 SVG 通常更清晰、也更轻。
如果用 <picture>,把最省的格式放前面,内层的 img 留一个兼容兜底:
<picture>
<source
type="image/avif"
srcset="/images/hero-1200.avif 1200w, /images/hero-2000.avif 2000w"
sizes="100vw"
/>
<source
type="image/webp"
srcset="/images/hero-1200.webp 1200w, /images/hero-2000.webp 2000w"
sizes="100vw"
/>
<img
src="/images/hero-1200.jpg"
width="1200"
height="800"
alt="装修完成的厨房,胡桃木橱柜配自然光"
/>
</picture>
img 仍然重要——它承载兜底源、alt、width、height。不要把无障碍信息或布局信息藏在 source 里。
实际能落地的质量档位
“质量数值”并没有跨工具的统一标准。一个编码器里的 JPEG 质量 80,和另一个编码器里的 80 未必等价;WebP 80、JPEG 80、AVIF 50 之间也不能画等号。把质量当成起手值,然后看导出结果。
| 输出 | 起手值 | 需要调高的时候 | 需要调低的时候 |
|---|---|---|---|
| JPEG 兜底 | 82–88 | 商品细节、人脸、图上文字 | 装饰性照片、背景、文件仍然过大 |
| WebP 照片 | 78–85 | Hero、商品、作品集图 | 缩略图、列表图、简单背景 |
| WebP 缩略图 | 70–78 | 文字或纹理看着发软 | 图很小但文件还是不轻 |
| AVIF 照片 | 45–65 | 出现色带,皮肤/织物/细节崩掉 | 大 Hero 依然太重 |
| PNG | 不涉及有损质量 | 需要清晰边缘的截图或透明素材 | 只有目标端支持时才考虑 WebP/AVIF |
一个常见误区是“为了保险”把所有图都导到 95 或 100。多数网页照片里,那些多出来的字节只会出现在网络瀑布图里,页面上并看不出差别。另一个误区是为了硬凑某个体积目标把质量压到 50 以下。如果得压这么狠,先别继续拉低质量,而是先缩尺寸或换格式。
按页面角色划分的体积目标
这些不是 Google 规则,也不是决定排名的魔法阈值。它们是实用的复审目标,帮你识别明显过重的图。
| 素材 | 健康的工作目标 | 备注 |
|---|---|---|
| 头像/作者头像 | 10–40KB | 通常 160–400 px 展示 |
| 卡片缩略图 | 15–60KB | 列表图尺寸应保持一致 |
| 博客正文图 | 60–180KB | 与宽度和细节量有关 |
| 商品列表图 | 50–150KB | 标签必须清晰可读 |
| 商品详情图 | 120–300KB | 为放大与纹理留余量 |
| 首屏 Hero | 150–450KB | 更大也可能合理,但要测 LCP |
| 全屏作品集照片 | 250–700KB | 有时候画质比严格体积更重要 |
| UI 截图 | 30–250KB | 文字清晰度胜过省几字节 |
一张 760 px 的博客图如果 900KB,多半有问题。一张整宽作品集照片 410KB 但效果极好,硬压到 90KB 反倒是走错方向。
LCP 和 Hero 图的压缩
最值得下功夫的图,往往就是首屏最大的那张。用 Core Web Vitals 的说法,它常常就是 Largest Contentful Paint 图。压小它有帮助——前提是它还要能被“早发现、早加载”。
处理 Hero 图时:
- 按页面里实际使用的宽高比裁切。
- 导出多档响应式宽度,例如 1200 px 与 2000 px。
- 如果栈支持,AVIF 放前面,WebP/JPEG 作兜底。
- 不要给 Hero 或首屏其他 LCP 候选加 lazy-load。
- 加上
width与height,让浏览器提前占位。 fetchpriority="high"只用在最有可能成为 LCP 元素的那一张上。
兜底 img 示例:
<img
src="/images/hero-1200.jpg"
srcset="/images/hero-1200.jpg 1200w, /images/hero-2000.jpg 2000w"
sizes="100vw"
width="1200"
height="800"
fetchpriority="high"
alt="装修完成的厨房,胡桃木橱柜配自然光"
/>
不要给整个图库都挂 fetchpriority="high"。优先级提示是把锋利的刀——留给那一张真的要最先到达的图。
怎么比较压缩结果
正确的比较不是“原图 vs 压缩图,100% 缩放”。那种比法只会让你说服自己继续发过大的图。要在访客真正看到的尺寸和上下文里比。
按这个流程走一遍:
- 把压缩后的图放到真实页面,或同宽的测试布局里。
- 桌面宽和手机宽都看一遍。
- 重点看容易出问题的区域:人脸、皮肤、天空、渐变、织物、商品标签、小字、以及高对比边缘。
- 在渲染尺寸下切换原图和压缩版。
- 只在很短的时间里 100% 放大,用来抓明显的伪影,不是为了追求没人会看到的完美。
不同格式的压缩伪影各有个性:JPEG 常见块状边缘、振铃、色噪;过压 WebP 会把纹理糊成一片;AVIF 推太狠会出现色带和塑料感;PNG 截图则容易走到另一头——看着完美,但重得离谱。
一个 PhotoTools 的网页图处理流程
PhotoTools 适合放在图片进入 CMS、CDN 或代码仓库之前。它替代不了完整的构建管线,但对小型站点、博客文章、给客户的预览稿以及一次性素材,它提供了一条干净的手工流程。
- 保留原始源文件,不动。
- 定角色:Hero、正文图、商品图、截图、缩略图或背景。
- 原图远大于展示尺寸时,先用 Resize。
- 打开 Compress,选 JPEG、WebP 或 AVIF,WebP/JPEG 从质量 80 附近起手。
- 点 “Compress all”,逐张看原始体积、输出体积、节省比例。
- 下载结果,放回页面上下文里检查。
- 视觉上不过关,就回到原图或缩放过的中间稿,换更高的质量重新导出。
- 还是过重,就先缩尺寸,再考虑把质量压进伪影区。
不要反复对已经压过的下载稿再压缩——有损伪影会叠加。回到母版或干净的缩放中间稿再来。
元数据与隐私
相机文件常常带 EXIF 元数据:GPS 坐标、拍摄时间、机身型号、镜头、编辑软件等。这些对访问者看图并没有帮助,反而可能泄露私人信息。
PhotoTools 的压缩流程是:解码文件、把像素画到浏览器的 canvas 上,然后导出一份新文件。MDN 文档提到,OffscreenCanvas.convertToBlob() 可以为支持有损压缩的格式指定图片类型和质量。由于输出是由 canvas 上的像素生成的,相机元数据通常不会被带入新文件。
涉及敏感照片时,请在发布前用元数据检测工具再验一次最终下载稿。隐私不只是文件大小的问题。
会让图看起来变差的常见错误
- 压缩早于缩放: 你在试图从“布局根本不会展示的像素”里省字节。
- 给照片用 PNG: 对相机图,PNG 通常大得离谱。
- 给带文字的截图用 JPEG: 体积或许更小,但文字会糊。
- 在错误尺寸下判断: 全分辨率放大会把无害的伪影渲染得触目惊心。
- 给所有设备只出一张巨大的 Hero: 手机用户白白下载了自己用不上的桌面像素。
- 给 Hero 加 lazy-load: 首屏以外的图可以 lazy-load,LCP 图不行。
- 不写
width和height: 图片加载时页面可能跳动。 - 对线上已压过的文件再压: 能回源就回源。
一份紧凑的发布前清单
上传一张网站图之前,走一遍:
- 这个格式适合当前内容类型吗?
- 源图宽度是不是基于真实展示宽度与合理 DPR 定的?
- 若移动端 Hero 有不同裁切,是否准备了更小的移动端候选?
- 质量档能不能撑住人脸、标签、渐变、商品细节?
- 文件大小对它的角色而言算合理吗?
- 页面上有没有
width、height、有意义的alt,以及在需要时的响应式srcset/sizes? - LCP 图是否 eager 加载并优先,首屏之外的图是否 lazy-load?
- 有没有把导出的图放回真实布局里看过?
- 是否留了原始源文件?
好的压缩流程是那种“合理地无聊”:挑对像素、挑对格式、用合理质量导出、放回真实页面里看、在图开始显出“加工感”之前收手。
参考的技术资料
本文对照了 PhotoTools 现行的压缩与缩放实现、web.dev 的图像性能指南、Chrome 的「Improve image delivery」洞察、Chrome 的「Properly size images」建议、MDN 的 OffscreenCanvas.convertToBlob() 文档、MDN 的图像文件类型指南 以及 Google 的 WebP 文档。