本文首发于政采云前端团队博客:性能优化——图片压缩、加载和格式选择
https://www.zoo.team/article/images-compress
相信大家都听说过 '258 原则(https://blog.csdn.net/weixin_42139375/article/details/83001248)' ,一个网站的性能好坏很大程度上会影响到用户的体验。
在我经历的多个电商与大屏项目的优化性能的项目后,我发现图片资源
的处理在网站性能优化中有着举足轻重的作用。
一般电商网站请求数据
在首屏加载的 145
个请求中图片资源请求占到了 75%
以上,在所有请求静态资源中图片也占有着很大的比重。可见图片优化的重要性。
不过在认识图片优化前我们先了解下二进制位数
与色彩呈现
的关系。
在计算机中,一般用二进制数来表示像素。在不同的图片格式中,像素与二进制位数之间对应的关系是不同的。一个像素对应的二进制位数越多,它能表示的颜色种类就丰富,成像效果也就越精致,图片所需的存储空间相应也会越大。
目前市场上优化图片资源的方式有很多,如压缩图片、选择正确格式、 CDN 加速、懒加载等。
压缩图片
相信是大家第一时间想到的方案。像我们比较熟悉的 tinpng (https://tinypng.com/),他的原理是通过有'选择性'地减少图像所要存储的颜色数量,来减少图片所要存储的内存。
“When you upload a PNG (Portable Network Graphics) file, similar colors in your image are combined. This technique is called “quantization”. By reducing the number of colors, 24-bit PNG files can be converted to much smaller 8-bit indexed color images.
下面我们来看下样例:
细节展示:
压缩图片
虽然在一定程度上可以减少我们请求的资源所需要的带宽
,但如果是用对了格式
在性能上往往会有质的改变。
JPEG
是最常用的图像文件格式。
支持极高的压缩率,可使文件传输、下载、预览速度大大加快。
利用可变的压缩比可以控制文件大小。
能够轻松地处理 1600 万种颜色,可以很好地再现全彩色的图像。
JPG
的有损压缩在轮播图
和背景图
的展示上确实很难看出破绽,但当它处理矢量图形和 Logo 等线条感较强、颜色对比强烈的图像时,人为压缩导致的图片模糊
会相当明显。因此不适宜用该格式来显示高清晰度
和线条感较强
的图像。
除此之外, JPG
并不支持对有透明度要求的图像进行显示,如果需要显示透明图片
还是需要另寻它路。
JPG
适用于呈现色彩丰富的图片,在我们日常开发中,JPG
图片经常作为大的背景图
、轮播图
或预览图
出现。打开某电商网站首页,即可看到大图片的处理几乎都是使用了 JPG
。
png 是一种采用无损压缩算法的位图格式。
体积太大
理论上来说,当你追求最佳的显示效果(详情展示图、图片有放大需求、摄影作品等),并且不在意存储大小或所需带宽时,可以使用 PNG-24 (https://baike.baidu.com/item/PNG/174154?fr=aladdin)。但实践当中,为了避免文件体积过大的问题,我们一般不用 PNG
去处理较复杂的图像。当我们遇到适合 PNG
的场景时,也会优先选择更为小巧的 PNG-8
。
亦或者需要处理有透明度或线条明显的图片时,也会采用 PNG
。如网站主 logo:
严格来说应该是一种开放标准的矢量图形语言。
不是所有的浏览器都支持 SVG,IE8 和早期版本都需要一个插件。
复杂的图片会降低渲染速度(只支持小图)。
SVG 是文本文件,我们既可以像写代码一样定义 SVG ,把它写在 HTML 里、成为 DOM 的一部分。用的比较多的就是 iconfont (https://www.iconfont.cn/)。我们可以通过设置模块的 fill
属性轻松适配图标的换肤功能,并通过 font-size
调节其大小。
一种基于 64 个可打印字符来表示二进制数据的方法。
Base64
和雪碧图
一样,是作为小图标解决方案而存在的。
“Base64 是一种用于传输 8Bit 字节码的编码方式,通过对图片进行 Base64 编码,我们可以直接将编码结果写入 HTML 或者写入 CSS ,从而减少 HTTP 请求的次数。
在 Elements
中搜索 “base64” 关键字,你会发现 Base64
也有很多使用的地方。而且它对应的图片占用内存较小。
既然 Base64
这么棒,我们把所有图片都用Base64
好了嘛。
Base64
编码后,图片大小会膨胀为原文件的 4/3
( Base64 编码原理 (https://blog.csdn.net/wo541075754/article/details/81734770))。如果我们把大图也编码到 HTML 或 CSS 文件中,后者的体积会明显增加,即便我们减少了 HTTP 请求,也无法弥补这庞大的体积带来的性能开销。也就是说我们牺牲的渲染性能
大于资源请求性能
,这样做不太值得。
我们可以看到,大多数用 Base64 编码的图片都是小图。
一种同时提供了有损压缩与无损压缩(可逆压缩)的图片文件格式。
支持有损无损
占用体积小
可支持透明
同 JPEG/JPG
。因为目前兼容性不好,一般搭配 JPEG/JPG
一起使用。
给大家整理了思维导图
:
我们原始的方式是将图片等资源一起放入项目中打包上线。
这样做的缺点在于打包出来的包大不说,用户请求资源的速度也会受到限制。比如我们的服务器在华南,华北的用户请求就会稍慢。当遇到并发量大的情况时,从部署服务器请求接口与资源这无外乎给我们的服务器提供了多余的压力。当我们临时想替换一张图片时,也需要重新打包并发布上线,非常麻烦。
当我们将图片进行 OSS 放置并 CDN 加速后,这个问题就得到了很好的解决。不同地区的用户可以访问就近服务器,重复的请求也会产生缓存,避免 OSS 流量的浪费。
《OSS 和 CDN 的区别》(https://www.cnblogs.com/jsfh/p/14076992.html) 大家也可以参考这篇文章进行细看。
相信大家一定会遇到首屏数据过多加载缓慢的情况。在这个情况下我们就需要考虑懒加载了。当用户滚动到预览位置时,在进行图片数据的请求。期间用骨架屏或缩略图代替。
window.onload = function () {
// 获取图片列表,即 img 标签列表
var imgs = document.querySelectorAll('img');
// 获取到浏览器顶部的距离
function getTop(e) {
return e.offsetTop;
}
// 懒加载实现
function lazyload(imgs) {
// 可视区域高度
var h = window.innerHeight;
// 滚动区域高度
var s = document.documentElement.scrollTop || document.body.scrollTop;
for (var i = 0; i < imgs.length; i++) {
//图片距离顶部的距离大于可视区域和滚动区域之和时懒加载
if ((h + s) > getTop(imgs[i])) {
// 真实情况是页面开始有2秒空白,所以使用 setTimeout 定时 2s
(function (i) {
setTimeout(function () {
// 不加立即执行函数i会等于9
// 隐形加载图片或其他资源,
// 创建一个临时图片,这个图片在内存中不会到页面上去。实现隐形加载
var temp = new Image();
temp.src = imgs[i].getAttribute('data-src');//只会请求一次
// onload 判断图片加载完毕,真是图片加载完毕,再赋值给 dom 节点
temp.onload = function () {
// 获取自定义属性 data-src,用真图片替换假图片
imgs[i].src = imgs[i].getAttribute('data-src')
}
}, 2000)
})(i)
}
}
}
lazyload(imgs);
// 滚屏函数
window.onscroll = function () {
lazyload(imgs);
}
}
性能优化
是我们前端开发工程师必须要掌握的一门硬技能。和学习其他新技术不同的是,当你想学习一套新的框架时,阅读文档和源码几乎可以让你在使用过程中游刃有余。但性能优化却不一样,它只能让我们去摸索去领悟去突破,它是一种经验也是一种习惯更是一种嗅觉。
最佳实践:使用阿里云 CDN 加速 OSS 访问 (https://developer.aliyun.com/article/770616?utm_content=g_1000173381)
掘金小册: 前端性能优化原理与实践 (https://juejin.cn/book/6844733750048210957)
壁纸网站: wellhaven (https://wallhaven.cc/)
如果你觉得这篇内容对你挺有启发,我想邀请你帮我两件小事
1.点个「在看」,让更多人也能看到这篇内容(点了「在看」,bug -1 😊)
政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 60 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。
如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com
联系客服