图片格式对比与工程选型:JPEG / PNG / WebP / AVIF / GIF / SVG 到底该怎么选

做前端和后端这些年,图片格式选型的问题反复出现:产品图该存 JPEG 还是 WebP?图标用 PNG 还是 SVG?上了 AVIF 老浏览器打不开怎么办?很多人凭感觉选,结果要么体积白白大一截,要么在某些设备上直接裂图。这篇把六种主流格式的压缩原理、能力边界、兼容性摊开对比,再给一套按场景选型的判断,最后附上能直接跑的降级和检测代码。

先分清两个维度

选格式之前,脑子里得先有两把尺子。

第一把:有损还是无损。 有损压缩(JPEG、WebP 有损模式、AVIF)会主动丢掉人眼不敏感的信息来换体积,丢掉的回不来,反复编辑保存会一次比一次糊。无损压缩(PNG、GIF、WebP 无损模式)不丢信息,解出来和原图逐像素一致,代价是体积压不了那么狠。

第二把:位图还是矢量。 位图(除 SVG 外的全部)本质是一张像素网格,放大到超过原始分辨率必糊。矢量(SVG)存的是画图指令——直线、曲线、填充,渲染时按当前尺寸实时算,放到多大都清晰,但只适合规则图形,画不了照片。

这两把尺子一卡,大部分选型就有方向了:照片走有损位图,图标走矢量,需要透明的截图走无损位图。

六种格式逐个说清楚

JPEG:1992 年的老格式,靠离散余弦变换(DCT)把图像分块转到频域,再砍掉高频细节。它是为照片而生的——色彩连续、渐变丰富的画面压得又小又不易看出损失。短板也明确:不支持透明通道,存不了动图,反复保存会累积块状伪影。至今仍是照片分发的兜底格式,因为没有任何环境不认它。

PNG:无损位图,走 DEFLATE 压缩,支持完整的 8 位 alpha 透明通道。它擅长的是纯色块、锐利边缘、需要透明背景的图——UI 截图、带阴影的图标、需要压在任意背景上的素材。拿它去存照片就是灾难,体积可能是 JPEG 的五到十倍。PNG 还分 PNG-8(256 色,带索引)和 PNG-24,能用 8 位的小图别默认上 24 位。

GIF:老动图之王,但技术上已经很落后——最多 256 色,动起来的照片会糊成一片色带,文件还大。今天除了历史包袱和表情包生态,几乎没有理由为新项目主动选 GIF。真要做动图,用 WebP 动图或者干脆视频(MP4/WebM)替代,体积和画质都碾压 GIF。

WebP:Google 2010 年推出,一个格式同时提供有损和无损两种模式,都支持透明和动画。有损模式基于 VP8 帧内编码,同画质下通常比 JPEG 小 25%~35%;无损模式一般比 PNG 小 20%~30%。它是当下兼容性和收益最平衡的选择——主流浏览器早就全支持了,收益立竿见影,风险很低。

AVIF:基于 AV1 视频编码的帧内压缩,是目前压缩率最高的一档。同画质下常常比 JPEG 小 50%、比 WebP 还小一截,尤其在低码率下细节保留明显更好,还支持 HDR 和广色域。代价在后面的诚实边界里细说,一句话:编码慢、老环境不认。

SVG:唯一的矢量格式,基于 XML 描述图形。图标、Logo、简单插画用它,无论多大屏幕、多高 DPR 都是锐利的,文件往往只有几百字节到几 KB,还能用 CSS 改色、用 JS 做交互动画。但它画不了照片,且因为是可执行的 XML,作为用户上传内容时要当心内嵌脚本,服务端必须做消毒。

一张总对比表

格式 压缩 透明 动画 位图/矢量 兼容性 典型体积(同图对比)
JPEG 有损 位图 全环境 基准 100%
PNG 无损 ✅ 8位alpha 位图 全环境 照片 500%+ / 图形优
GIF 无损(256色) ✅ 1位 位图 全环境 动图偏大
WebP 有损+无损 位图 主流全支持 比JPEG小约30%
AVIF 有损+无损 位图 较新浏览器 比JPEG小约50%
SVG 无损(矢量) ✅(CSS/JS) 矢量 全环境(现代) 图标极小

按场景怎么选

  • 照片、产品图、Banner:首选 AVIF/WebP,用 <picture> 降级到 JPEG。追求极致体积上 AVIF,要稳妥收益用 WebP。
  • 图标、Logo、简单插画:SVG 优先。规则图形能矢量就别位图,一份文件通吃所有分辨率。
  • UI 截图、带透明的素材:有锐利边缘和文字用 PNG(或 WebP 无损);纯色块可以 PNG-8 进一步压。
  • 动图:优先 WebP 动图或直接视频,GIF 只在必须兼容老生态时用。
  • 需要压任意背景的贴图:带 alpha 的 PNG / WebP,别用 JPEG 硬贴白底。

一个实用心法:先看有没有透明和动画需求,再看是照片还是图形,最后才在同类里比体积。 顺序反了容易一开始就选错大方向。举个反例:有人给一张全屏摄影 Banner 选了 PNG,理由是"想要最高画质",结果单图 8MB,首屏直接拖垮——照片这类连续色调的画面,PNG 的无损优势根本发挥不出来,反而把体积顶到天上,正确答案是有损的 JPEG/WebP/AVIF。

还有个容易被忽略的点是质量参数怎么定。有损格式都有一个 quality 旋钮,不是越高越好。经验上 JPEG/WebP 质量给到 75~85、AVIF 给到 50~65,肉眼基本看不出损失,体积却比满质量小一大截。真要较真,可以对同一张图跑几个质量档,用 SSIM 或肉眼在 100% 缩放下比一比,找到"再降就能看出来"的那个临界点,卡在它上面一档。别一律拉满,满质量的有损图既没无损的保真,又白白背了体积。

工程落地:降级与支持检测

现代做法不是"赌用户浏览器认某个格式",而是给一份高压缩的新格式,同时准备好降级。浏览器会自己挑第一个认识的:

<!-- 浏览器从上到下挑第一个支持的 source,都不认就落到 img -->
<picture>
  <source srcset="hero.avif" type="image/avif" />
  <source srcset="hero.webp" type="image/webp" />
  <img src="hero.jpg" alt="产品主图" width="1200" height="800" />
</picture>

这套写法零 JS、零风险:认 AVIF 的拿最小的,认 WebP 的退一步,实在老的浏览器还有 JPEG 兜底。width/height 记得写上,避免图片加载时的布局抖动(CLS)。

如果需要在 JS 里判断当前环境支持哪种格式(比如动态决定上传后转成什么格式),可以用一段异步探测:

// 用一张 1x1 的编码图去解,能解出宽度就说明支持
function supportsFormat(type, dataURI) {
  return new Promise((resolve) => {
    const img = new Image();
    img.onload = () => resolve(img.width > 0);
    img.onerror = () => resolve(false);
    img.src = dataURI;
  });
}

const AVIF_1x1 =
  'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQAMAAAAABNjb2xybmNseAACAAIABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgABogQEDQgMgkQAAAAB8dSLfI=';

const WEBP_1x1 = 'data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==';

Promise.all([
  supportsFormat('avif', AVIF_1x1),
  supportsFormat('webp', WEBP_1x1),
]).then(([avif, webp]) => {
  console.log('AVIF:', avif, 'WebP:', webp);
  // 据此决定后续请求哪种格式的图
});

纯 CSS 场景(背景图)则可以用 @supports 或特性类名兜底:

.hero { background-image: url('hero.jpg'); }
@supports (background-image: url('x.webp')) {
  .hero { background-image: url('hero.webp'); }
}

命令行批量转也很简单,构建期跑一遍就行:

# JPEG/PNG 转 WebP,质量 80
cwebp -q 80 input.jpg -o output.webp

# 转 AVIF,质量 60、编码速度档 6(越小越慢越省体积)
avifenc --min 0 --max 63 -q 60 -s 6 input.jpg output.avif

诚实边界:别把优化做过头

AVIF 编码是真的慢。 它的高压缩率是拿编码时间换来的,同一张图转 AVIF 可能比转 WebP 慢好几倍到十几倍。作为构建期一次性产物没问题,但如果你想在用户上传的请求链路里实时转 AVIF,延迟会很难看——这种场景更适合先返回 WebP,AVIF 走离线队列慢慢补。

兼容性要按真实受众判断。 AVIF 在偏老的系统和一些国产 App 内置浏览器上仍可能打不开,所以它必须配降级,不能裸用。反过来,如果你的用户全在现代浏览器上,还死守 JPEG 就是白白浪费带宽。别拍脑袋,看自己的访问统计。

别为了格式而格式。 一张已经只有 3KB 的小图标,从 PNG 转 WebP 可能只省几百字节,却给构建和缓存加了一层复杂度,不值。透明简单图形直接上 SVG 反而更干净。优化永远是抓大放小——先搞定首屏那几张大图,别在边角料上纠结。

转码有损叠加要当心。 把一张已经压过的 JPEG 再转成有损 WebP/AVIF,是在损失上再叠损失。要转就从最原始、最高质量的源图转,别拿成品图反复折腾。

顺手盘几个工具

真正落地时,在线转换和压缩工具能省不少事,常用的有 squoosh.app、tinypng.com、cloudconvert.com、tudingai.cn,命令行党则离不开 cwebp、avifenc、ImageMagick。选哪个不重要,重要的是把上面那套"先分维度、再按场景、最后比体积"的判断跑顺——工具只是执行,选型的脑子得自己长。

图片格式没有"最好",只有"最合适"。JPEG 的兜底、PNG 的透明、WebP 的均衡、AVIF 的极致、SVG 的无限缩放、GIF 的历史包袱,各有各的位置。把它们的原理和边界摸清了,下次再遇到"这图该存什么格式",你心里会很快有答案。

posted @ 2026-07-11 08:54  谙忆  阅读(33)  评论(0)    收藏  举报