All Tools / Blog / 如何为网页压缩图片而不损失质量

如何为网页压缩图片而不损失质量

2 min read

大图片是网页加载缓慢的最常见原因。一张手机拍摄的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像素的手机屏幕。