目录
前言
说到前端的性能优化,必不可少的要讲到对图片的优化,大部分网站页面的构成都少不了图片的渲染,尤其一些电商网站,页面的主要组成部分都是图片。因此当页面需要引入大量的图片时却又不对图片进行优化,页面的加载速度就不容乐观了。
此外,雅虎军规和 Google 官方的最佳实践也都将图片优化列为前端性能优化必不可少的环节——图片优化的优先级可见一斑。(ps: 说白了,前端性能优化,必须对图片下狠手)。
何为图片的优化
就图片这块来说,与其说我们是在做“优化”,不如说我们是在做“权衡”。因为我们要做的事情,就是去压缩图片的体积(或者一开始就选取体积较小的图片格式)。但这个优化操作,是以牺牲一部分成像质量为代价的。因此我们的主要任务,是尽可能地去寻求一个质量与性能之间的平衡点。
不同业务场景下的图片方案选型
图片格式
- JPEG/JPG
- PNG
- Base64
- SVG
- WebP
不同图片格式的优缺点和应用场景
JPEG/JPG
关键字
有损压缩、体积小、加载快、不支持透明
优点
优点:JPG 最大的特点是有损压缩。这种高效的压缩算法使它成为了一种非常轻巧的图片格式。另一方面,即使被称为“有损”压缩,JPG的压缩方式仍然是一种高质量的压缩方式:当我们把图片体积压缩至原有体积的 50% 以下时,JPG 仍然可以保持住 60% 的品质。此外,JPG 格式以 24 位存储单个图,可以呈现多达 1600 万种颜色,足以应对大多数场景下对色彩的要求,这一点决定了它压缩前后的质量损耗并不容易被我们人类的肉眼所察觉——前提是你用对了业务场景。
缺点
有损压缩在在大图,如背景图、轮播图确实很难露出马脚,但当它处理矢量图形和 Logo 等线条感较强、颜色对比强烈的图像时,人为压缩导致的图片模糊会相当明显。
此外,JPEG 图像不支持透明度处理,透明图片需要召唤 PNG 来呈现。
应用场景
JPG 适用于呈现色彩丰富的图片,在我们日常开发中,JPG 图片经常作为大的背景图、轮播图或 Banner 图出现。使用 JPG 呈现大图,既可以保住图片的质量,又不会带来令人头疼的图片体积,是当下比较推崇的一种方案。
PNG
关键字
无损压缩、质量高、体积大、支持透明
优点
PNG(可移植网络图形格式)是一种无损压缩的高保真的图片格式。
PNG 图片具有比 JPG 更强的色彩表现力,对线条的处理更加细腻,对透明度有良好的支持。它弥补了上文我们提到的 JPG 的局限性,唯一的 BUG 就是体积太大。
缺点
PNG 体积较大,较旧的浏览器和程序可能不支持 PNG 文件。
应用场景
复杂的、色彩层次丰富的图片,用 PNG 来处理的话,成本会比较高,我们一般会交给 JPG 去存储。考虑到 PNG 在处理线条和颜色对比度方面的优势,我们主要用它来呈现小的 Logo、颜色简单且对比强烈的图片或背景等。
扩展
PNG-8 与 PNG-24 的选择题
什么时候用 PNG-8,什么时候用 PNG-24,这是一个问题。
理论上来说,当你追求最佳的显示效果、并且不在意文件体积大小时,是推荐使用 PNG-24 的。
但实践当中,为了规避体积的问题,我们一般不用PNG去处理较复杂的图像。当我们遇到适合 PNG 的场景时,也会优先选择更为小巧的 PNG-8。
如何确定一张图片是该用 PNG-8 还是 PNG-24 去呈现呢?好的做法是把图片先按照这两种格式分别输出,看 PNG-8 输出的结果是否会带来肉眼可见的质量损耗,并且确认这种损耗是否在我们(尤其是你的 UI 设计师)可接受的范围内,基于对比的结果去做判断。
SVG
关键字
文本文件、体积小、不失真、兼容性好
优点
和性能关系最密切的一点就是:SVG 与 PNG 和 JPG 相比,文件体积更小,可压缩性更强。 当然,作为矢量图,它最显著的优势还是在于图片可无限放大而不失真这一点上。这使得 SVG 即使是被放到视网膜屏幕上,也可以一如既往地展现出较好的成像品质——1 张 SVG 足以适配 n 种分辨率。此外,SVG 是文本文件。我们既可以像写代码一样定义 SVG,把它写在 HTML 里、成为 DOM 的一部分,也可以把对图形的描述写入以 .svg 为后缀的独立文件(SVG 文件在使用上与普通图片文件无异)。这使得 SVG 文件可以被非常多的工具读取和修改,具有较强的灵活性。
缺点
一方面是它的渲染成本比较高,这点对性能来说是很不利的。另一方面,SVG 存在着其它图片格式所没有的学习成本(它是可编程的)。
应用场景
SVG 是可编程的,因此可以在WEB项目中的平面图绘制,如需要绘制线,多边形,图片等。 SVG也可作为iocn图标,个人认为作为图标使用的话, 在线矢量图形库已经满足大部分的业务需求了。
Base64
关键字
文本文件、依赖编码、小图标解决方案
优点
base64就是一串字符串码表示的图片,在加载页面和js时一块加载出来,减少了加载图片时的http请求。加载一张图片时会发起一次http请求,http请求每次建立都会需要一定的时间,对于加载一张小图来说,下载图片所需的时间会比建立http请求的时间要短。
缺点
既然 Base64 这么棒,我们何不把大图也换成 Base64 呢?
这是因为,Base64 编码后,图片大小会膨胀为原文件的 4/3(这是由 Base64 的编码原理决定的)。如果我们把大图也编码到 HTML 或 CSS 文件中,后者的体积会明显增加,即便我们减少了 HTTP 请求,也无法弥补这庞大的体积带来的性能开销,得不偿失。 在传输非常小的图片的时候,Base64 带来的文件体积膨胀、以及浏览器解析 Base64 的时间开销,与它节省掉的 HTTP 请求开销相比,可以忽略不计,这时候才能真正体现出它在性能方面的优势。 因此,Base64 并非万全之策,我们往往在一张图片满足以下条件时会对它应用 Base64 编码:
- 图片的实际尺寸很小(大家可以观察一下掘金页面的 Base64 图,几乎没有超过 2kb 的)
- 图片无法以雪碧图的形式与其它小图结合(合成雪碧图仍是主要的减少 HTTP 请求的途径,Base64 是雪碧图的补充)
- 图片的更新频率非常低(不需我们重复编码和修改文件内容,维护成本较低)
应用场景
Base64应用场景往往是比较小的图片,如:页面的Logo。对于一些体积较大的图片,由于Base64的缺点不建议转成Base64的格式。
如果你使用vue框架,就应该知道, vue-cli创建的webpack模板默认会将10K以下的图片和字体文件转为base64。好处带来了更快的渲染,不会因为页面切换时还有加载图片的延迟感。
如何修改vue的默认配置
vue-cli2.0
找到build/webpack.base.conf.js
{// 对图片资源文件使用url-loader
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
// 小于10K的图片转成base64编码的dataURL字符串写到代码中
limit: 10000,
// 其他的图片转移到静态资源文件夹
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
vue-cli3.0
需要自己创建vue.config.js
文件
module.exports = {
chainWebpack: config => {
config.module
.rule('images')
.use('url-loader')
.loader('url-loader')
.tap(options => Object.assign(options, { limit: 20000 }))
}
// limit的数值即可修改图片进行base64转换文件的大小限制
WebP
关键字
年轻的全能型选手
WebP 是今天在座各类图片格式中最年轻的一位,它于 2010 年被提出, 是 Google 专为 Web 开发的一种旨在加快图片加载速度的图片格式,它支持有损压缩和无损压缩。
优点
WebP 像 JPEG 一样对细节丰富的图片信手拈来,像 PNG 一样支持透明,像 GIF 一样可以显示动态图片——它集多种图片文件格式的优点于一身。
WebP 的官方介绍:
与 PNG 相比,WebP 无损图像的尺寸缩小了 26%。在等效的 SSIM 质量指数下,WebP 有损图像比同类
JPEG 图像小 25-34%。 无损 WebP 支持透明度(也称为 alpha 通道),仅需 22% 的额外字节。
对于有损 RGB 压缩可接受的情况,有损 WebP 也支持透明度,与 PNG 相比,通常提供 3 倍的文件大小。
图片优化是质量与性能的博弈,从这个角度看,WebP 无疑是真正的赢家。
缺点
WebP 纵有千般好,但它毕竟太年轻。我们知道,任何新生事物,都逃不开兼容性的大坑。
此外,WebP 还会增加服务器的负担——和编码 JPG 文件相比,编码同样质量的 WebP 文件会占用更多的计算资源。
应用场景
现在限制我们使用 WebP 的最大问题不是“这个图片是否适合用 WebP 呈现”的问题,而是“浏览器是否允许 WebP”的问题,即我们上文谈到的兼容性问题。具体来说,一旦我们选择了 WebP,就要考虑在 Safari 等浏览器下它无法显示的问题,也就是说我们需要准备方案B,准备降级方案。
目前真正把 WebP 格式落地到网页中的网站并不是很多,这其中淘宝首页对 WebP 兼容性问题的处理方式就非常有趣。
<img src="//img.alicdn.com/tps/i4/TB1CKSgIpXXXXccXXXX07tlTXXX-200-200.png_60x60.jpg_.webp" alt="手机app - 聚划算" class="app-icon">
同样的一张图片,在 Safari 中的后缀从 .webp 变成了 .jpg!说明站点是先进行了兼容性的预判,在浏览器环境支持 WebP 的情况下,优先使用 WebP 格式,否则就把图片降级为 JPG 格式(本质是对图片的链接地址作简单的字符串切割)。
此外,还有另一个维护性更强、更加灵活的方案——把判断工作交给后端,由服务器根据 HTTP 请求头部的 Accept 字段来决定返回什么格式的图片。当 Accept 字段包含 image/webp 时,就返回 WebP 格式的图片,否则返回原图。这种做法的好处是,当浏览器对 WebP 格式图片的兼容支持发生改变时,我们也不用再去更新自己的兼容判定代码,只需要服务端像往常一样对 Accept 字段进行检查即可。
小结
对图片的前端性能优化,就是在保证图片质量的情况下尽可能的压缩图片的大小。对于前端攻城狮来说,合适的应用场景选择合适的图片格式尤为重要。
参考学习
掘金小册《前端性能优化原理与实践》
我想对你说
如果算上学习前端的那段时间的话,那么入前端这一行已经两年了。从开始的只会开机关机到现在可以独立去完成一个页面的开发,并负责公司前端的主要业务。其中的幸运占了很大一部分,有时候自己都有点飘了,感觉自己好像挺厉害的,从开始的Angular、vue到现在uni-app,其实啥也不是,回顾待在公司的一年多,每天疲于公司的业务,自己的个人技术成长有限。虽搭建了自己的个人博客,但自己的事自己心里清楚,好多的内容要么是东凑凑西凑凑,要么就是写的比较浅,真正做到完全理解的又有几篇。我很怕自己每天假装很忙却又什么都没做,很怕自己认为自己每天都在学习,到最后发现那只是自欺欺人的外在表现。
独坐桌前,深思良久不知如何敲下接下来的“豪言壮志”,算了吧!想写一些与君共勉的话,但道理君与我都懂,何必去揭露自己心中无点墨的实事呢。
最后总该说些什么吧
“早睡早起,锻炼身体”,“好好学习,天天向上”
睡觉,晚安。