图片在网页应用中的占据了大部分的下载数据并占据着页面的大部分可视空间,因此在图片的优化可以显著减少网页下载数据并提升网页性能。
图片的优化既是一门艺术同时也是一门科学。说它是艺术因为没有一个确定的方法去压缩某个特定的图片,而说它是科学因为已经有很多成熟的技术和方法可以很大程度上减小图片的体积。
移除替换图片
- 移除没有必要的图片资源
- 尽可能充分利用CSS3效果
- 使用web fonts替换图片中的编码文字
首先要思考图片是否必要,在实现预期效果的前提下尽可能的减少图片的使用。图片并不是越多越好,一张在合适位置的图片可能抵得过千言万语。
其次要考虑的是可不可以使用其他的技术来代替图片的效果:
- CSS效果(渐变,阴影等) 和CSS动画可以用来制作不受分辨率影响的组件,其占用的资源要远小于图片文件。
- Web fonts 可以让开发者使用漂亮的字体,同时保留了选取,搜索,方法缩小的功能。
在图片中使用编码文字会带来一系列问题:文字不可选取,不可搜索,不可放大缩小,不可操作更改,而且对高分辨率屏幕很不友好。
矢量图片 vs 栅格图片
- 矢量图片适合用于那些包含几何图形的图片
- 矢量图片不受缩放以及分辨率限制
- 栅格图片适合用于包含不规则图形及细节的复杂场景
图 | 矢量图片:
图 | 栅格图片:
- 矢量图片利用线、点以及多边形来表示图片
- 栅格图片通过编码每个方形像素点来表示图片
每种图片格式都有其优点和缺点:矢量图片适合包含简单图形的图片,例如logo, 文字,图标等等,其在各种分辨率和缩放比例下都能实现锐利的显示,因此适合需要显示在高分辨率显示屏以及不同尺寸屏幕上的组件。
但是对于复杂场景,例如照片,使用矢量图片会导致图片失真,因此应当使用栅格图片格式,例如GIF, PNG, JPEG或者更新的格式JPEG-XR和WebP。
由于栅格图片不能适应于各种分辨率和缩放尺寸,因此需要保存多个版本的图片以发送给不同的用户。
高分辨率屏幕的影响
- 高分辨率屏幕上每个CSS像素(CSS pixels)包含多个设备像素(device pixels)
- 高分辨率图片需要多得多的像素和字节
- 图片优化技术是相同的,和分辨率无关
当我们谈论图片像素时,应当区分两种不同的像素:CSS像素和设备像素,一个CSS像素可能包含多个设备像素,这就意味着一个CSS像素包含的设备像素越多,显示出来的图片细节就越好,如下图所示:
图 | CSS像素和物理像素
高DPI(HiDPI)屏幕会带来更好的显示效果,但是代价也是显而易见的,那就是我们的图片需要更多的细节来填满更多的设备像素。矢量图片可以很好地解决这个问题,但是对于栅格图片,更高的分辨率意味着需要更多的像素以及更大的文件体积,例如一张显示在100x100(CSS)像素上的照片:
图 | 分辨率对文件大小的影响
可以看到当分辨率翻倍时,文件大小会增大四倍,因此对于高分辨率屏幕应尽量使用矢量图片,如果一定要使用栅格图片,应根据不同屏幕发送不同版本的图片,可参考 srcset and pictures
优化矢量图片
所有的现代浏览器都支持SVG格式图片。它是一种基于XML的适用于二维图形的图片格式。我们可以将SVG标签直接插入页面,也可以从外部引入。大部分的基于矢量的绘图软件都可以生成SVG文件,当然也可以手工编辑SVG文本。
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.2" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 612 792" xml:space="preserve">
<g id="XMLID_1_">
<g>
<circle fill="red" stroke="black" stroke-width="2" stroke-miterlimit="10" cx="50" cy="50" r="40"/>
</g>
</g>
</svg>
这段代码是从Adobe Illustrator中直接生成的一绘制个圆形的SVG文件。可以看出它包含了很多没必要的元数据,例如图层信息,注释。要舍弃掉这些多余数据,可以使用工具 svgo 。此外可以通过GZIP压缩来进一步减小文件的传输体积。
优化栅格图片
- 栅格图片是像素组成的网格
- 每个像素中包含着颜色和透明度信息
- 图片压缩器使用各种技术来减少每个像素所需要的字节数从而达到减小图片体积的目的
一个栅格图片是一个个像素组成的二维网格,每个像素储存着“RGBA”值:(R)红色通道,(G)绿色通道,(B)蓝色通道和(A)alpha(透明度)通道
浏览器为每个通道分配了256个值,相当于每个通道8位 (bits),一个像素4字节 (bytes),因此通过图片栅格大小可以很容易算出文件大小:
- 100 x 100像素图片由10000个像素组成
- 10000个像素 X 4字节 = 40000 字节
- 40000字节 / 1024 = 39 KB
一个简单的压缩策略是减少“位深 (bit-depth)”,8位通道可以为每个通道定义256个值,一个像素 (RGB通道共24位) 可以实现16M种颜色。如果只实现256个颜色的话,RGB通道总共只需要8位,这样一个像素就节省了2个字节 (16位 = 2字节)
备注: 从左到右(PNG),32位 (16M种颜色),7位 (128种颜色),5位 (32种颜色)
带有渐变色的复杂场景需要更多位的图片以避免图片锯齿化,相反的, 如果图片很简单,使用高位图片是浪费资源 。
另一个压缩图片的方法是通过处理相近的同色像素,这种方法称为 delta encoding
有损和无损压缩
由于人眼的工作机理,当我们为了减小文件体积而丢弃一些像素信息的时候人眼并不会察觉。例如人眼对不同的颜色有不同的敏感度,这意味着我们可以使用更少的位数来编码某些颜色。一个典型的图片压缩工作流包含两个主要步骤:
- 图片通过“有损”过滤器来 消除 掉一些像素数据
- 图片通过”无损“过滤器来 压缩 像素数据
第一个步骤是可选的,具体的算法取决于图片格式,但是值得注意的是任何图片都可以通过有损压缩来减小体积。事实上不同的图片格式的区别就是他们在进行有损和无损压缩时采用的算法。
具体使用何种压缩方式取决去图片内容以及在图片体积和质量之间的平衡。
PHOTOSHOP导出JPEG格式图片时可以选取图片质量,实际上就是在控制有损和无损压缩的算法。需要注意的是不同图片格式下的”质量“是没有可比性的:quality 90的JPEG图片和quality 90的WebP图片是完全不同的。即使同一图片同一质量下,每次压缩得到的结果也可能是不同的!
选取正确的图片格式
除了不同的无损和有损压缩方法,不同的图片格式还支持不同的特性,例如动画和透明。因此选取合适的图片格式需要统筹考虑预期的视觉效果以及功能要
求。
图 | 不同图片格式的特性
有三种图片格式是所有浏览器都支持的:GIF, PNG, JPEG,除此之外,一些浏览器还支持一些新的图片格式例如WebP和JPEG XR,它们提供了更好的压缩以及更多的特性,那么如何决定使用哪种格式呢?
图 | 图片格式选取
- 如果需要动画,GIF是唯一的选择
- GIF支持最多256色,因此对大多数图片来说不是个好选择,另外,PNG-8在少色的情况也能提供更好的压缩,因此只有需要动画的时候考虑GIF
- 如果需要保留更多细节,更高分辨率,选择PNG
- PNG除了可选颜色范围外不进行任何的有损压缩,因此它可以产生最高质量的图片,但相应的图片体积也会比其他格式更大
- 如果图片组件包含几何图形,考虑矢量图片格式(SVG)
- 如果图片组件包含文字,考虑修改,因为图片中的文字不可选取、搜索、缩放。考虑使用web font
- 如果要优化照片,截图或相似图片组件,使用JPEG
- JPEG格式通过有损和无损压缩组合来减小图片体积,尝试不同的质量等级来实现图片体积和质量之间的平衡
最新的图片格式例如WebP和JPEG XR可以显著减小图片体积,研究表明和同等质量的JEPG图片相比,WebP图片可以节约30%的体积。 webp
由于WebP和JPEG XR的支持性不好,可以采取如下几个策略:
- 一些CDN提供图片优化服务,包括JPEG XR和 WebP推送
- 一些开源工具(例如PageSpeed for Apache或Nginx)可以自动优化,转换并推送合适的图片
- 可以通过判断客户端对图片格式的兼容性来推送合适的图片格式
压缩工具
要通过尝试不容的压缩方法选择最优的优化方案。
推送缩放后的图片组件
图片优化主要从两个方面入手:优化每个像素的数据体积以及优化图片的像素数量,因此最简单的网页优化方法就是确保发送到前端的图片的大小就是实际显示的大小。听起来容易,但是多数情况下发送到网页端的图片都比实际显示的要大,需要通过浏览器缩放显示,这不仅占用CPU资源,而且影响图片显示的分辨率。在Chrome开发者工具中可以查看图片的实际尺寸和显示尺寸。
要尽量避免多余像素的发送,发送到前端的图片的实际尺寸要尽可能的和显示尺寸相同。 一点点图片缩放就可能产生很多的多余像素,从而导致很多没必要的数据体积。如下图所示:
图 | 图片缩放导致的多余像素
总结
- 尽量使用矢量图片格式
- 尽可能压缩SVG组件
- 挑选最合适的栅格图片格式
- 通过试验确定最合适的图片质量等级
- 舍弃不必要的图片元数据
- 发送的图片要尽量和显示的图片尺寸相同
- 尽可能多的使用自动化工具