一、图片格式对比
我们通常使用的图片就是gif、png和jpg了。
其中,gif格式是比较老的图片格式,它的色彩效果最低(就是不清楚!!!),如果想要使用gif保存鲜艳图片会让你的网站看上去非常可怕。 但是gif有着不可忽视的优点:体积小、有着极好的压缩效果,支持动画,并且支持透明效果,虽然这个透明没有PNG格式图片支持的强大。。。 动画选择gif没有错,如果你的图片只有单调的色彩, 没有渐变色,例如只有红蓝两色,那么选择gif就再好不过了。
另外,PNG图片可以说是最适合网络的图片了,优点就是 无损压缩,压缩比率很高, 可渐变透明, 几乎具备所有GIF的优点, 缺点是不如JPG格式的颜色色彩丰富, 同样的图片体积也比JPG略大,但是PNG图片应该是网站设计上最为推广的,比如Google就是一个很好的例子,它的所有站点中几乎都是使用的PNG格式, 而且8位的PNG完全可以替代掉GIF。
**
JPG
JPG格式的图片应该是使用场景最多的图片的格式了,由于JPG格式采用了极其高效的压缩算法,使其能在压缩50%甚至60%的情况下依旧可以保持不错的图片质量,因此在网站设计中使用类似背景图,轮播图等大图时都会考虑使用JPG格式的图片,但是JPG始终是有损压缩,在对线条感较强或者颜色比较丰富的图片做人为压缩时,可能会出现失真的情况,同时它也不支持透明度处理
PNG
PNG格式的图片特点大家都知道,就是高保真无损压缩,当对图片设计有较高要求时,首选PNG格式,显示高清细腻,但是它也有明显的问题就是体积过大
SVG
SVG格式图片有个显著特点就是它是可编程的,是基于xml语法的,同时作为矢量图,它可以无限放大而不变形,因此可以方便的对不同手机屏幕做自适应,相比于PNG和JPG它的体积更小,只有1kb甚至更小,但是它最大的缺陷就是渲染成本过高,因此我们在选择一些小且色彩单一的图标时可以考虑使用SVG格式的图片,如图
一般情况下,我们会将SVG格式的图片上传到iconfont上,这样不仅方便管理而且方便使用,同时iconfont上还有许多其他设计师设计的优秀小图标可以直接拿来使用,是不是很方便呢?
WebP与Gif
这两兄弟我们一般都是用来展示动图的,但是WebP也可以用来展示静态图片,WebP最大的优点就是无损压缩,体积小,但是浏览器支持太差,我们来看caniuse的数据:
从图上可以看到WebP格式在苹果设备和IE上基本不支持,因此浏览器的不支持是它的硬伤,因此在对动图做展示的时候我们不得不选gif,即便它的体积很大,渲染开销也大
**
各方面比较
- 大小比较:通常地,PNG ≈ JPG > GIF
- 透明性:PNG > GIF > JPG
- 色彩丰富程度:JPG > PNG >GIF
- 兼容程度:GIF ≈ JPG > PNG
几种文件格式的选用依据
- 颜色丰富的照片,JPG是通用的选择
- 如果需要较通用的动画,GIF是唯一可用的选择
- 如果图片由标准的几何图形组成,或需要使用程序动态控制其显示特效,可以考虑SVG格式
- 如果需要清晰的显示颜色丰富的图片,PNG比较好
参考
二、优化方案
1. 降低图片的大小
1.1 选择合适的图片格式
- 动图:gif,webp(webp在ie,safari存在兼容性问题)
- 静态图(透明):png8>png24
-
1.2 压缩工具:
- https://tinypng.com/
2. 响应式图片
2.1 通过服务器图片资源配置命名规则来获取图片
<img src="bgimg-320.jpg" />或<img src="bgimg-480.jpg" />
2.2 通过css定义来加载不同的背景bg图片
@media only screen and (max-width : 480px) {.img {background-image: url(bg-480.jpg);}}@media only screen and (max-width : 360px) {.img {background-image: url(bg-360.jpg);}}
2.3 img的srcset和sizes的方法
这两个img属性是html5的属性,有浏览器的兼容问题
<img class="img" src="imgbg-320.jpg"srcset="imgbg-320.jpg 320w, imgbg-360.jpg 360w, imgbg-480px.jpg 480w"sizes="(max-width: 480px) 480px, 320px">
- src:当设备不支持srcset,sizes属性时,使用这个图片
- srcset指定图片的地址和对应的图片质量。
- sizes用来设置图片的尺寸零界点
对于srcset和sizes,详解点击查看sizes="[media query] [length], [media query] [length] ... "
2.4 picture标签实现
通过媒体查询的方式,根据页面宽度(当然也可以添加其他参考项)加载不同图片,具体picture,详情点击查看<picture><source srcset="3.jpg" media="(min-width: 320px)"><source srcset="2.jpg" media="(min-width: 480px)"><img srcset="1.jpg"></picture>
3. 减少HTTP的网络资源请求
3.1 CSSSprites(背景精灵图/雪碧图)
一种网页图片应用处理方式,将一个页面涉及到的所有零星图片或者图标都包含到一张大图里面,这样就只需要加载这个一个图片,而不是很多个图片了,这样就减少了很多http的请求。
如何使用雪碧图?
- 利用ps,sketch等制图软件制作雪碧图,利用CSS的background-image,background- repeat,background-position的组合进行背景定位,background-position可以用数字精确的定位出背景图片的位置。详情点击查看
- 利用webpack插件
- webpack-spritesmith:参考浅探前端图片优化
3.2 css和css3制作简单的图标和动画(代替gif图片)
随着技术的发展,css3可以实现的效果越来越多,比如箭头图标,三角形,梯形等图标,或者一些阴影效果,渐变的效果,所以可以用css制作一些简单的图标,而且具有多变性。.sanjiaoxing {width: 0;height: 0;border-top: 2em solid #000;border-right: 1.8rem solid transparent;border-left: 1.8rem solid transparent;}
3.3 SVG技术替换图片
SVG 是使用 XML 来描述二维图形和绘图程序的语言,支持透明,缩放,动画。
- webpack-spritesmith:参考浅探前端图片优化
什么是SVG?
- SVG 指可伸缩矢量图形 (Scalable Vector Graphics)
- SVG 用来定义用于网络的基于矢量的图形SVG 使用 XML 格式定义图形
- SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失
- SVG 是万维网联盟的标准
- SVG 与诸如 DOM 和 XSL 之类的 W3C 标准是一个整体
3.4 html5 canvas绘画图形
目前canvas应用很多,它可以使用脚本javascript来绘制各种图表、动画等,点击查看更多3.5 base64
将一个图片地址进行base64编码后会得到一串字符串,将这个字符直接放到img的src属性上,你会发现浏览器是可以识别这一串字符的,不需要发送网络请求直接解析,这样就可以达到减少网络请求的目的,但是base64编码后的图片质量比原图图片质量要大,因此也只会在一些质量较小的图标类图片上面使用,否则得不偿失,常见使用base64编码的方案就是webpack的url-loader,举个例子:
上面的这个配置就是把8k一下的通过url-loader进行base64编码,转换成一串dataurlmodule.exports = {module: {rules: [{test: /\.(png|jpg|gif)$/,use: [{loader: 'url-loader',options: {limit: 8192}}]}]}}
4. 字体图库代替图标
随着技术的更新和浏览器的更新,字体图库去代替一些图标我认为还是极好的,使用字体图库你不仅可以改变大小,而且还可以改变颜色,大家比较熟知的的字体图库有很多,主要推荐两个:
- font-awesom:bootstrap在使用
- iconfont:出自阿里
5. 图片延迟加载(懒惰加载)
有个页面会很大很长很多的图片素材,这样全部加载就会变的很慢,因此需要修改一下加载方案,只加载窗口内的图片,我们大家浏览网站的时候会经常看到会有默认图,图片加载成功之后会替换默认图,这是与预加载相反的:
- 能有效的提高页面加载速度
- 有时候可以帮助减少服务器负载
技术方案:
- js/lazyload.js
- IntersectionObserver:IntersectionObserver提供给我们一项能力:可以用来监听元素是否进入了设备的可视区域之内,这意味着:我们等待图片元素进入可视区域后,再决定是否加载它,毕竟用户没看到图片前,根本不关心它是否已经加载了。 这是Chrome51率先提出和支持的API,而在2019年的今天,各大浏览器对它的支持度已经有所改善(除了IE,全线崩~)
- Chrome的黑科技—loading属性
后两项查看《谈谈Web应用中的图片优化技巧及反思》了解详细信息
6. JPG/JPEG压缩与渐进式图片
压缩jpg/jpeg图片的方式与png类似,imagemin提供了两个插件:jpegtrain和mozjpeg供我们使用。一般我们选择mozjpeg,它拥有更丰富的压缩选项:
npm install imagemin-mozjpegconst imagemin = require('imagemin');const imageminMozjpeg = require('imagemin-mozjpeg');(async () => {await imagemin(['images/*.jpg'], 'build/images', {use: [imageminMozjpeg({ quality: 65, progressive: true })]});console.log('Images optimized');})();
注意到我们使用了progressive: true选项,这可以将图片转换为渐进式图片,关于渐进式图片,它允许在加载照片的时候,如果网速比较慢的话,先显示一个类似模糊有点小马赛克的质量比较差的照片,然后慢慢的变为清晰的照片:
而相比之下,非渐进式的图片(Baseline JPEG)则会老老实实地从头到尾去加载:
张鑫旭大神的这篇文章,可以帮你更好地了解两者的区别: 渐进式jpeg(progressive jpeg)图片及其相关 简单来说,渐进式图片一开始就决定了大小,而不像Baseline图片一样,不断地从上往下加载,从而造成多次回流,但渐进式图片需要消耗CPU去多次计算渲染,这是其主要缺点。 当然,交错式png也可以实现相应的效果,但目前pngquant没有实现转换功能,但是ps中导出png时是可以设置为交错式的。
在真实项目中如何操作?
实际项目中,总不能UI丢一个图过来你就跑一遍压缩代码吧?幸好imagemin有对应的webpack插件,在webpack遍地使用的今天,我们可以轻松实现批量压缩:
先安装imagemin-webpack-plugin:
npm install imagemin-webpack-plugin
接着在webpack配置文件中,引入自己需要的插件,使用方法完全相同。具体可参考github的文档 imagemin-webpack-plugin:
import ImageminPlugin from 'imagemin-webpack-plugin'import imageminMozjpeg from 'imagemin-mozjpeg'module.exports = {plugins: [new ImageminPlugin({plugins: [imageminMozjpeg({quality: 100,progressive: true})]})]}
锦上添花
但这里还有个问题,当网速慢的时候,图片还没加载完之前,用户会看到一段空白的时间,在这段空白时间,就算是渐进式图片也无法发挥它的作用,我们需要更友好的展示方式来弥补这段空白,有一种方法简单粗暴,那就是用一张占位图来顶替,这张占位图被加载过一次后,即可从缓存中取出,无须重新加载,但这种图片会显得有些千篇一律,并不能很好地做到preview的效果。 这里我向大家介绍另一种占位图做法——css渐变色背景,原理很简单,当img标签的图片还没加载出来,我们可以为其设置背景色,比如:
<img src="a.jpg" style="background: red;"/>
这样会先显示出红色背景,再渲染出真实的图片,重点来了,我们此时要借用工具为这张图片”配制”出合适的渐变背景色,以达到部分preview的效果,我们可以使用 https://calendar.perfplanet.com/2018/gradient-image-placeholders/ 这篇文章中推荐的工具GIP进行转换,这里附上在线转换的地址 https://tools.w3clubs.com/gip/ 经过转换后,我们得到了下面这串代码:
background: linear-gradient(to bottom,#1896f5 0%,#2e6d14 100%)
最终效果如下所示:
三、预加载
方案1
将background-image CSS属性放在HTML文件的head中,该文件将比CSS文件中的文件更早开始下载。
方案2
在页面加载完毕后,执行一次背景图素材的预加载:
// 定义需要预加载的图片数组(可以是本地文件也可以是绝对地址)const imgList = [require("@img/a-large-image-01.png"),require("@img/a-large-image-02.png"),require("@img/a-large-image-03.png"),require("@img/a-large-image-04.png")// ...]// 定义预加载函数function imgPreload(imgArr){for(let i=0; i<imgArr.length; i++){const newIMG = new Image();newIMG.src = imgArr[i];}}// 执行预加载imgPreload(imgList);
只要不创建dom,对页面的外观是没有影响的,图片只要请求成功了,后续再调用这个图片地址就无需重新请求了,本地已有缓存可快速显示。详情查看《弹窗大背景优化方案 png大图片预加载处理方法》
四、总结
图片优化的手段总是随着浏览器特性的升级,网络传输协议的升级,以及用户对体验要求的提升而不停地更新迭代,几年前适用的或显著的优化手段,几年后不一定仍然如此。因地制宜,多管齐下,才能将其优化做到极致!
