如何为网页压缩图片而不损失质量
大图片是网页加载缓慢的最常见原因。一张手机拍摄的4 MB照片,在博客文章中以800像素宽度显示,视觉效果与60 KB的优化版本完全相同——但在移动网络上下载速度慢60倍。
本文介绍如何有效压缩图片:选择正确格式、设置质量参数,以及为生产环境自动化压缩流程。
有损压缩与无损压缩
有损压缩丢弃人眼不易察觉的像素数据——渐变中的色彩变化、失焦区域的高频噪点。JPEG和WebP使用有损压缩,通过质量参数(0–100)控制权衡。
无损压缩在不丢弃任何数据的情况下重新组织数据。PNG使用无损压缩。用oxipng这样的无损优化器处理PNG可以获得更小的文件,质量零损失。
大多数网页图片适合有损压缩。例外情况:徽标、含文字的截图,以及任何像素化会很明显的内容。
选择正确的格式
| 格式 | 最适合 | 说明 |
|---|---|---|
| WebP | 照片、UI截图 | 相同质量下比JPEG小25–35%;所有现代浏览器支持 |
| JPEG | 照片 | 通用支持;有损;不支持透明 |
| PNG | 徽标、图标、含文字截图 | 无损;支持透明;比WebP大 |
| AVIF | 照片 | 比JPEG小50%;编码较慢;浏览器支持仍在普及中 |
| SVG | 图标、徽标、图表 | 分辨率无关;矢量图文件极小 |
默认规则:将照片和UI截图转换为WebP。有透明度的图片保留为PNG(或带Alpha的WebP)。矢量图使用SVG。
有效的质量设置
JPEG和WebP的质量75–85是网页标准目标。低于70会在照片中出现可见的压缩失真;高于85保存的数据在视觉上没有区别。
| 使用场景 | 质量 |
|---|---|
| 缩略图(≤200像素) | 60–70 |
| 博客图片、产品照片 | 75–80 |
| 主图、横幅 | 80–85 |
| 打印参考质量 | 90+ |
在浏览器中操作
对于单张图片,拖入图片压缩工具,调整质量滑块,下载压缩版本。工具完全在客户端运行——图片不会离开你的设备。
命令行:sharp(Node.js)
sharp 是最快的Node.js图像处理库,封装了libvips。
npm install sharp
const sharp = require('sharp');
// 将JPEG转换为质量80的WebP
sharp('input.jpg')
.webp({ quality: 80 })
.toFile('output.webp')
.then(info => console.log(info));
// 调整尺寸并压缩
sharp('hero.png')
.resize(1200) // 调整为1200像素宽,保持纵横比
.webp({ quality: 82 })
.toFile('hero.webp');
批量处理整个目录:
const sharp = require('sharp');
const fs = require('fs');
const path = require('path');
const inputDir = './images/original';
const outputDir = './images/compressed';
fs.readdirSync(inputDir)
.filter(f => /\.(jpg|jpeg|png)$/i.test(f))
.forEach(file => {
sharp(path.join(inputDir, file))
.webp({ quality: 80 })
.toFile(path.join(outputDir, file.replace(/\.(jpg|jpeg|png)$/i, '.webp')));
});
命令行:ImageMagick
ImageMagick在大多数Linux/macOS系统上可用,支持几乎所有格式。
# 安装
brew install imagemagick # macOS
sudo apt install imagemagick # Ubuntu
# 质量80的JPEG压缩
convert input.jpg -quality 80 output.jpg
# 转换为WebP
convert input.jpg -quality 80 output.webp
# 调整为最大1200像素宽,然后压缩
convert input.jpg -resize 1200x -quality 80 output.webp
# 批量将文件夹中所有JPEG转换为WebP
for f in *.jpg; do convert "$f" -quality 80 "${f%.jpg}.webp"; done
命令行:cwebp(Google的WebP编码器)
# 安装
brew install webp # macOS
sudo apt install webp # Ubuntu
# 质量80转换
cwebp -q 80 input.jpg -o output.webp
# 检查结果
webpinfo output.webp
Python:Pillow
from PIL import Image
# 打开并压缩为JPEG
with Image.open('input.png') as img:
img.convert('RGB').save('output.jpg', 'JPEG', quality=80, optimize=True)
# 打开并压缩为WebP
with Image.open('input.jpg') as img:
img.save('output.webp', 'WebP', quality=80)
批量压缩并显示进度:
from PIL import Image
from pathlib import Path
input_dir = Path('images/original')
output_dir = Path('images/compressed')
output_dir.mkdir(exist_ok=True)
for img_path in input_dir.glob('*.{jpg,jpeg,png}'):
with Image.open(img_path) as img:
out_path = output_dir / img_path.stem
img.save(f'{out_path}.webp', 'WebP', quality=80)
print(f'{img_path.name}: {img_path.stat().st_size // 1024}KB → {(out_path.with_suffix(".webp")).stat().st_size // 1024}KB')
响应式图片——不只是压缩,还要调整尺寸
将3000像素宽的图片压缩到质量80仍然会产生较大的文件。网页的正确做法是根据设备提供不同尺寸。
<img
srcset="
hero-400.webp 400w,
hero-800.webp 800w,
hero-1200.webp 1200w
"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
src="hero-1200.webp"
alt="主图"
loading="lazy"
/>
用sharp生成各尺寸:
const sharp = require('sharp');
const widths = [400, 800, 1200];
for (const w of widths) {
sharp('hero.jpg')
.resize(w)
.webp({ quality: 80 })
.toFile(`hero-${w}.webp`);
}
压缩效果参考
将24位PNG/JPEG照片转换为质量80的WebP时的典型结果:
| 原始文件 | 格式 | 压缩后 |
|---|---|---|
| 3.2 MB(手机JPEG) | WebP q80 | 280–400 KB |
| 1.1 MB(PNG截图) | WebP q80 | 80–150 KB |
| 800 KB(产品照片JPEG) | WebP q80 | 60–120 KB |
已压缩的JPEG效果较小。PNG照片(无损编码)转换为有损WebP时效果最大。
要点总结
- 将照片和截图转换为WebP——相同质量下比JPEG小25–35%。
- 质量75–85是照片的网页标准目标。
- 徽标和有透明度的图片使用PNG或带Alpha的WebP。
- 批量处理用
sharp(Node.js)或Pillow(Python)。 - 通过
srcset提供多种尺寸——不要把3000像素的图片发给400像素的手机屏幕。