常遇问题:1.加载的图片太多导致向服务器请求的次数太多;2.图片太大导致每次请求的时间过长,页面加载完成慢。
解决目标:减少资源到客户端的延迟。
那么问题来了,应该如何解决呢?
优化方法
1.将图片服务和应用服务分离(从架构师的角度思考)
对于服务器来说,图片始终是最消耗系统资源的,如果将图片服务和应用服务放在同一服务器的话,应用服务器很容易会因为图片的高I/O负载而崩溃,所以当网站存在大量的图片读写操作时,建议使用图片服务器。(注:图片服务器是专门为图片读写操作优化的独立服务器,运行网站的服务器称为应用服务器。)
另外,浏览器在同一时间对同一域名下的资源的并发请求数目是有限制的,一般在2-6之间,超过限制数目的请求就会被阻塞。把图片服务器与应用服务器分开,图片服务器采用独立域名 ,css、js和图片就可以并发请求了。
2.图片质量压缩(简单粗暴)
图片压缩应该是图片优化时最常用的方案,因为很简单,只需要将图片上传到tinypng或者智图等第三方软件的在线压缩图片平台,对图片进行压缩,就可以得到较小的图片质量。
3.图片懒加载
像淘宝或者京东这样的APP页面上有很多图片,当我们滑到下一屏时下一屏的图片才会加载,这就采用了图片懒加载的方式。
图片懒加载的目的就是为加快页面加载速度而做的,为了不让图片一次全部加载出来,通过将图片地址存放在一个img标签的属性上,当图片被滚动到页面上时,再将src属性替换成图片地址来达到懒加载的效果。(通过js将img标签的data-src属性赋值给src属性)
4.css Sprites(即雪碧图)
当网站或者APP有大量小icon,如果上传到图片服务器比如CDN,要加载所有这些小icon将增加大量请求,而CDN是按流量收费的,这无疑将增加很多成本。
雪碧图就是将这些小icon合并成一张图片,只需要加载一次,减少图片的网络请求,每次通过background-position来控制显示icon。(个人通常使用gopng这个网站在线生成,还可以自动生成对应的css代码)
不过这也有一定的缺点:在长期开发多人合作的项目中,会不好维护这些sprites,每次对icon做修改,都得相应的改动css里background-position的值,相当繁琐。
5.将图片压缩成base64格式来节约请求
将图片压缩成base64,随html或者css一起下载到浏览器,不需要额外的请求,这样就节约了请求。
将一个图片地址进行base64编码后会得到一串字符串,将这个字符直接放到img的src属性上,你会发现浏览器是可以识别这一串字符的,不需要发送网络请求直接解析,这样就可以达到减少网络请求的目的,但是base64编码后的图片质量比原图图片质量要大,因此也只会在一些质量较小的图标类图片上面使用,否则得不偿失,常见使用base64编码的方案就是webpack的url-loader,举个例子:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
}
}
上面的这个配置就是把8k以下的通过url-loader进行base64编码,转换成一串DataUrl。
针对decode base64编码的图片比较慢的问题,我们可以选择使用canvas来加速。当向canvas发出绘画命令时,浏览器直接将指令发到图形加速器而不需要开发者更多的干预,硬件图形加速器则以难以执行的运算速度实时绘画和渲染图形。因此,我们可以使用canvas来渲染base64编码后的图片。
6.css替换简单图标
这个优化方案应该都懂,其实就是在写代码之前先考虑一下设计稿里面的哪些内容是可以通过代码来实现的,能通过代码实现的尽量用代码实现,同时实现的时候多考虑绘制性能,能使用css3做GPU硬件加速的就尽量使用css3属性,这些都能减少图片使用而且不影响渲染性能。
7.响应式图片加载
什么是响应式图片加载?其实就是在不同分辨率的设备上显示不同尺寸的图片,避免资源的浪费,常用的方法就是css3的媒体查询(media query),来看个例子:
@media screen and (max-width: 375px) {
img {
background-image: url('phone.png');
}
}
@media screen and (max-width: 768px) {
img {
background-image: url('tablet.png');
}
}