HTTP Archieve 有个统计,图片内容已经占到了互联网内容总量的 62%,也就是说超过一半的流量和时间都用来下载图片。从性能优化的角度看,图片也绝对是优化的热点和重点之一,Google PageSpeed 或者 Yahoo 的 14 条性能优化规则无不把图片优化作为重要的优化手段,本文覆盖了 Web 图片优化的方方面面,从基本的图片格式选择、到尚未被广泛支持的响应式图片均有所提及。
Google Web Fundamentals 的说法我很喜欢:
图片优化既是一门艺术,也是一门科学,图片优化是一门艺术,是因为单个图片的压缩不存在最好的特定性方案,而图片优化之所以是一门科学,是因为许多开发得很出色的方法和算法可以明显减小图片的大小。要找到图片的最优设置,需要按照许多维度进行认真分析:格式能力、编码数据内容、像素尺寸等。
真的要用图片吗?
要实现需要的效果,真的需要图片吗?这是首先要问自己的问题。浏览器和 Web 标准的发展速度极快,记得数年前我在用微软 Silverlight 1.0 写视频播放器的时候,中文还不能使用自定义字体显示,所以那时候写了很多糟糕的代码把需要的文字在服务器上生成图片并缓存起来。用户下载起来很慢,搜索引擎也完全无法检索这些文字。
但是现在不一样了,很多特效(渐变、阴影、圆角等等)都可以用纯粹的 HTML、CSS、SVG 等加以实现,实现这些效果少则寥寥数行代码,多则加载额外的库(一张普通的照片比非常强大的效果库也大了许多)。这些效果不但需要的空间很小,而且在多设备、多分辨率下都能很好的工作,在低级浏览器上也可以实现较好的功能降级。因此在存在备选技术的情况下,应该首先选择这些技术,只有在不得不使用图片的时候才加入真正的图片。
备选技术
- CSS 效果、CSS 动画。提供与分辨率无关的效果,在任何分辨率和缩放级别都可以显示得非常清晰,占用的空间也很小。
- 网络字体。现在连很多图标库都是用字体方式提供,保持文字的可搜索性同时扩展显示的样式。
前端工程师最好能和设计师、产品经理保持沟通,帮助他们了解到什么样的效果比较“简洁、高效、可维护”,毕竟对于 CSS 来说改变圆角矩形的 Radius 可以实时看到效果,用图片的话至少要重新生成图片、切图并替换资源。Retina、高分辨率屏幕、多尺寸的设备,这些都加快了非图片特效的发展,想想在高分辨率屏幕下 Windows 7 的惨不忍睹,就知道原生的图片资源绝对不是多多益善。
图片格式的选择
如果效果真的需要图片来表现,那么选择图片格式是优化的第一步。我们经常听到的词语包括矢量图、标量图、SVG、有损压缩、无损压缩等等,我们首先说明各种图片格式的特点
图片格式 | 压缩方式 | 透明度 | 动画 | 浏览器兼容 | 适应场景 |
---|---|---|---|---|---|
JPEG | 有损压缩 | 不支持 | 不支持 | 所有 | 复杂颜色及形状、尤其是照片 |
GIF | 无损压缩 | 支持 | 支持 | 所有 | 简单颜色,动画 |
PNG | 无损压缩 | 支持 | 不支持 | 所有 | 需要透明时 |
APNG | 无损压缩 | 支持 | 支持 | Firefox、Safari、iOS Safari | 需要半透明效果的动画 |
WebP | 有损压缩 | 支持 | 支持 | Chrome、Opera、Android Chrome、Android Browser | 复杂颜色及形状、浏览器平台可预知 |
SVG | 无损压缩 | 支持 | 支持 | 所有(IE8 以上) | 简单图形,需要良好的放缩体验、需要动态控制图片特效 |
其中 APNG 和 WebP 格式出现的较晚,尚未被 Web 标准所采纳,只有在特定平台或浏览器环境可以预知的情况下加以采用,虽然均可以在不支持的环境中较好的功能降级,但本节暂不讨论这两种格式。图片格式选择过程如下:
颜色丰富的照片,JPG 是通用的选择
- 人眼的结构很适合查看 JPG 压缩后的照片,可以充分的忽略并在脑中补齐细节
- JPG 在压缩率不高时保留的细节还是不错的
- WebP 能够比 JPG 减少 30% 的体积,但目前兼容性较差
如果需要较通用的动画,GIF 是唯一可用的选择
- GIF 支持的颜色范围为 256 色,而且仅支持完全透明/完全不透明
- GIF 在显示颜色丰富的动画时可能出现颜色不全、边缘锯齿等问题
如果图片由标准的几何图形组成,或需要使用程序动态控制其显示特效,可以考虑 SVG 格式
- SVG 是使用 XML 定义的矢量图形,生成的图片在各种分辨率下均可自由放缩
- SVG 中可以通过 JavaScript 等接口自由变换图片特效,可以完成其中部分元素的自由旋转、移动、变换颜色等
如果需要清晰的显示颜色丰富的图片,PNG 比较好
- PNG-8 能够显示 256 种颜色,但能够同时支持 256 阶透明,因此颜色数较少但需要半透明的情景(如微信动画大表情)可以考虑 PNG-8
- PNG-24 可以显示真彩色,但不支持透明,颜色丰富的图片推荐使用(如屏幕截图、界面设计图)
- PNG-32 可以显示真彩色,同时支持 256 阶透明,效果最好但尺寸也最大
图片尺寸的选择
尺寸,曾经是最不需要讨论的话题,但自从 Retina 出现之后世界就变得复杂多了。关于移动设备上的像素和尺寸,展开说足够写一篇论文,我建议想详细了解的同学参考下面的文章:
这里只说我们关心的部分和结论,我们需要分清不同类型的像素:CSS 像素和设备像素。一个 CSS 像素可能包含多个设备像素。对于图片来说,在高 DPI 的屏幕上需要使用分辨率更高的图片,如果我们讨论的是 Retina,那么就需要 2 倍分辨率(几乎 4 倍尺寸)的图片。这几乎没有取巧的空间,屏幕就是那么大,需要的图片也就是那么大。(鸽子为什么那么大?^_^)
我们能够控制的地方是“恰好”显示所需尺寸的图片。例如在屏幕中通过 CSS 或者标签的 wihth/height 属性,将一副 200x200 的图片调整为 100x100 大小,那么这其中就有(200x200)-(100x100)=30000 个像素是浪费的,这占到了图片尺寸的 75%!
之所以有这么大的浪费,是因为图片的尺寸与面积基本成正比,与宽高的平方成正比。因此良好的计算客户端实际显示的图片尺寸,能够大大减小图片的大小。即使只有长和宽都只有 10px 被浪费,但是当图片足够大时,这部分也将产生很大影响。
响应式图片
上面提到“恰好”显示客户端所需大小的图片,听上去很容易不是吗?但当响应式布局出现后,这就变得极其困难。我们要支持上至 1920 宽度,下至 320 宽度的无数种设备,如果使用 1920 宽度的图片,那么在小型设备(这类设备往往对网速和流量更加敏感)上每个用户都要付出额外的带宽和等待时间,如果使用 320 宽度的图片,那么在 1920 的屏幕上就像是在高清屏上使用 DOS 那么让人难以接受。
很自然的,我们需要图片也能“响应式”加载,根据所在设备的不同,加载不同尺寸的图片。响应式图片尚没有写入 Web 标准,实现起来也有诸多不便和兼容性限制。我建议参考百度 EFE 团队的这篇文章:
响应式图片虽然尚未成为标准,但这是 Web 图片优化的一柄利器,一旦被广泛支持,再没有比缩小图片尺寸更有效的优化方法了。
优化 JPG 和 PNG
选择了正确的图片格式,按照正确的大小生成了图片后,我们还需要对图片进行进一步优化,这种优化一般分两步进行:
- 有损优化,删除没有出现或极少出现过的颜色,合并相邻的相近颜色。这一步并不必须,如 PNG 格式就直接进入下一步
- 无损优化,压缩数据,删除不必要的信息
JPG 和 PNG 格式的图片生成后,一般还有进一步优化的空间,例如 JPG 格式的照片中,可能携带有相机的 Exif 信息,PNG 格式的图片中可能带有 Fireworks 等软件的图层信息等。去除这些额外信息后,还可以通过减小图片的调色板,去除没有出现过的颜色,以及合并相邻的相同颜色等手段来进行优化。原理性的内容这里不再赘述,仅介绍工程中可用的优化工具。
不同格式的图片有一系列工具,这些工具有有更多种参数调节方案,常见的几种调节工具有:
工具 | 用途 |
---|---|
jpegtran | 优化 JPG 图片 |
OptiPNG | 无损 PNG 优化 |
AdvPNG | 无损 PNG 优化 |
PNGQuant | 有损 PNG 优化 |
如果你真的需要追求各种图片的极限压缩,可以参阅这些工具的文档,但是对于一般的 Web 应用,面对的图片种类多样,几乎不可能在工程中实现对每种工具的独立配置,因此推荐使用以下工具来进行优化。这些工具往往使用了上表中的一种或几种优化工具。
ImageOptim (Mac)
Mac 平台下非常赞的图片优化工具,只需要把需要优化的图片拖拽进 ImageOptim,就能够完成对图片的优化。设置选择的也很丰富,目前支持 JPG 和 PNG 的优化。这是我在写文章时最常用到的工具,把网站用到的图片拖进去,优化就完成了~
Kraken (Web)
在免费模式下可以上传图片,优化后打包下载,很多国外企业也选择了它的收费服务。亲自测试 Kraken 的图片优化结果比 ImageOptim 一般要小 3% 左右,效果不错,当然价格也不错。适合偶尔有图片优化需求,或者不在开发机上没有优化软件可以使用的情况。
智图 (Web)
腾讯 ISUX 团队有篇文章介绍智图:http://isux.tencent.com/zhitu.html
国货当自强,腾讯的智图工具推出不久,但实测效果很好,而且提供了 Gulp 的自动化支持,这部分会在后面自动优化章节介绍。只想建议一句,Kraken 的首页比智图美好几百倍…… 而且把压缩前的 PNG 和压缩后的 JPG 放在一起对比大小,真的没关系么~
优化 SVG
IE9 及以上的浏览器都支持可缩放矢量图(SVG),SVG 是基于 XML 的图片格式,适用于二维图片。可以将 SVG 标记直接嵌入网页,也可以作为外部资源嵌入。可以通过大多数基于矢量的绘图软件创建 SVG 文件。这是一段简单的 SVG 图形:
这个圆形轮廓为黑色,背景为红色,从 Adobe Illustrator 直接导出。可以从中看到大量元数据,例如图层信息、注释和 XML 名称空间等等,在浏览器中呈现资源时,通常不需要这些数据。因此我们需要使用一些工具去除这些不必要的元数据,仅保留必须的标记。
SVGO 工具可以缩减 SVG 文件的体积,在这个的例子中,SVGO 能够将 Illustrator 生成的 SVG 文件大小减小 58%,从 470 字节缩减到 199 字节。
在我自己的网站中,对于网站 Logo 一类的图标比较倾向于使用 SVG,而且由于 SVG 是基于 XML 的格式,本质上是纯文本,所以,还可以采用 GZIP 压缩来进一步减小传输大小,当然这需要一些服务器配置,例如在 apache 服务器中设置:
AddType image/svg+xml .svg
AddOutputFilterByType DEFLATE image/svg+xml
来对 SVG 文件启用 GZip 压缩(当然你还需要先加载 deflate 模块并进行适当配置,GZip 的配置超出了本文的范畴,这部分内容请自行 Google)
优化 GIF 和 APNG
GIF 有很多好处,在颜色数较低的时候能够大幅减小图片体积,而且他也是唯一能够较为通用的展示动画的图片格式。关于 GIF 格式的优化原理我并不熟悉,只是在工程中直接使用成型的压缩工具,在后文自动优化章节的 Grunt 中,会介绍通过 Grunt Task 进行自动优化的方法。
关于 APNG,目前浏览器对他的支持还不够好,不过在支持 HTML5 的场景中,有成熟的开源工具 apng-canvas 可以用于支持 APNG。
腾讯 ISUX 团队有篇文章介绍 iSparta 工具:http://isux.tencent.com/introduction-of-apng.html。这是目前几乎唯一能够批量处理 APNG 文件的工具,感兴趣的同学可以在那篇文章里得到更多地了解。
自动优化
前面说了太多关于如何优化各种不同格式图片的方法和工具,优化图片需要大量重复性的劳动,作为工程师显然不会忍受这一点,因此也产生出了很多工具对图片进行自动优化,这里主要介绍 CDN、Grunt/Gulp、Google PageSpeed 三种方式。
自动优化:CDN
使用 CDN 对图片自动进行优化,我在国外的 CDN 提供商处很少见到这类服务,倒是国内的两大新秀 CDN 七牛和又拍在这方面都做了大量工作。其工作方式为,向 CDN 请求图片的 URL 参数中包含了图片处理的参数(格式、宽高等),CDN 服务器根据请求生成所需的图片,发送到用户浏览器。
七牛云存储的图片处理接口极其丰富,覆盖了图片的大部分基本操作,例如:
- 图片裁剪,支持多种裁剪方式(如按长边、短边、填充、拉伸等)
- 图片格式转换,支持 JPG, GIF, PNG, WebP 等,支持不同的图片压缩率
- 图片处理,支持图片水印、高斯模糊、重心处理等
七牛云存储的图片处理接口使用并不复杂,例如下面这张原图:
我们通过如下 URL 请求,裁剪正中部分,等比缩小生成 200x200 缩略图:
http://qiniuphotos.qiniudn.com/gogopher.jpg?imageView2/1/w/200/h/200
自动优化:Grunt/Gulp
这里介绍用于图片优化的 Grunt 组件:grunt-image。前端工程师的重复性工作,例如合并静态资源、压缩 JS 和 CSS 文件、编译 SASS 等都可以使用 Grunt 等自动化工具批量完成,图片优化也是如此。
grunt-image 非常强大,按照作者的介绍,其内部加载的图片优化工具包括了 pngquant, optipng, advpng, zopflipng, pngcrush, pngout, mozjpeg, jpegRecompress, jpegoptim, gifsicle 和 svgo。支持批量自动优化 PNG, JPG, SVG 和 GIF,速度也不错,配置方式支持单图片优化和全目录优化:
module.exports = function (grunt) {
grunt.initConfig({
image: {
// 指定单独的图片优化
static: {
options: {
pngquant: true,
optipng: true,
advpng: true,
zopflipng: true,
pngcrush: true,
pngout: true,
mozjpeg: true,
jpegRecompress: true,
jpegoptim: true,
gifsicle: true,
svgo: true
},
files: {
'dist/img.png': 'src/img.png',
'dist/img.jpg': 'src/img.jpg',
'dist/img.gif': 'src/img.gif',
'dist/img.svg': 'src/img.svg'
}
},
// 指定图片目录进行优化
dynamic: {
files: [{
expand: true,
cwd: 'src/',
src: ['**/*.{png,jpg,gif,svg}'],
dest: 'dist/'
}]
}
}
});
grunt.loadNpmTasks('grunt-image');
};
自动优化:Google PageSpeed
Google 做事风格比较彻底,看见哪个软件不好用就拿来直接 fork 出新版本或者干脆重写,对于 Web 优化,Google 发布了了 Google PageSpeed 这个服务器模块,可以在 apache 或 ngnix 中加载,通过在服务器配置文件中进行设置来进行自动化的优化。对于图片格式转换、图片优化甚至图片 LazyLoad 都有相关选项。这部分展开会非常长,请感兴趣的同学参考 Google 的手册。
感谢原作者,博客转自(墙外):https://www.cnblogs.com/wizcabbit/p/web-image-optimization.html
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于