图像优化问题主要可以分为两方面:图像的选取和使用,图像的加载和显示。
图像基础
HTTP Archive上的数据显示,网站传输的数据中,60%的资源都是由各种图像文件组成的,当然这些是将各类型网站平均的结果,单独只看电商类网站,这个比例可能会更大,如此之大的资源占比,同样意味着有很大的优化空间。
图像是否必需
图像资源优化的根本思想:压缩。无论是选取何种图像的文件格式,还是针对于同一种格式压缩至更小的尺寸,其本质都是用更小的资源开销来完成图像的传输和展示。
我们首先需要思考下要达到期望的信息传递效果,是否需要图像?这不仅是因为图像资源与网页上的其他资源(html/css/js等)相比有更大的字节开销,出于对节省资源的考虑,对用户注意力的珍惜也很重要,如果一个页面打开之后有很多图像,那么用户其实很难快速梳理出有效的信息,即便获取到了也会让用户觉得很累。一个低感官体验的网站,它的价值转化率不会很高。
当确定了图像的展示效果必须存在时,在前端实现上也并非一定就要用图像文件,还存在一些场景可以使用更高效的方式来实现所需的效果。
- 网站中一个图像在不同的页面或不同的交互状态下,需要呈现不同的效果(边角的裁切、阴影或渐变),其实没有必要准备不同效果的图像,使用css即可,相对于一张图像文件的大小来讲,修改其所增加的css代码量忽略不计。
- 如果一个图像上面需要显示文字,建议通过网页字体的形式通过前端代码进行添加,而不是使用带文字的图像,其原因一方面是包含了更多信息的图像文件一般会更大,另一方面图像中的文本信息代码的用户体验一般较差(不可选择、搜索以及缩放),并且在高分辨率设备上的显示效果也会大打折扣。
因此,我们在选择使用某种资源之前,如果期望达到更优的性能效果,则需要先思考这种选择是否必须。
矢量图和位图
当确定了图像是实现展示效果的最佳方式时,接下来就是选择合适的图像格式。图像文件可以分为两类:矢量图和位图。
- 矢量图
矢量图的优点时能够在任何缩放比例下呈现出细节同样清晰的展示效果。其缺点是对细节的展示效果不够丰富,对足够复杂的图像来说,比如要达到照片的效果,若通过svg进行矢量图绘制,则所得文件会大的离谱,但即便如此也很难达到照片的真实效果。目前几乎所有的浏览器都支持svg。
svg标签所包括的部分就是该矢量图的全部内容,除了必要的绘制信息,可能还包括一些元数据,比如xml命名空间、图层以及注释信息。但这些信息对浏览器绘制一个svg来说不是必要的,所以在使用之前可通过工具去除这些元数据来达到压缩的目的。 - 位图
位图是通过对一个矩阵中的栅格进行编码来表示图像的,每个栅格只能编码表示一个特定的颜色,如果组成图像的栅格像素点越多且每个像素点所能表示的颜色范围越广,则位图图像的显示效果就会越逼真,当然图像文件也就越大。虽然位图没有像矢量图那种不受分辨率影响的优秀特性,但对于复杂的照片却能提供较为真实的细节体验。
分辨率
在前端开发过程中书写css时,经常会为图像设置显示所需的长宽像素值,但在不同的设备屏幕上,有时候相同的图像以及相同的设置,其渲染出来的图像会让人明显感觉出清晰度有差别。产生这个现象的原因涉及两种不同的分辨率:屏幕分辨率和图像分辨率。
图像分辨率展示的就是该图像文件所包含的真实像素值,比如一个200px200px的分辨率的图像文件,它就定义了长宽各200各像素点的信息。设备分辨率则是显示器屏幕所能显示的最大像素值,比如一台电脑的显示器分辨率为2560px1600px。更高的设备分辨率有助于显示更绚丽多彩的图像,这其实很适合矢量图的发挥,因为其不会失真。而对于位图来说,只有图像文件包含更多的像素信息时,才能更充分地利用屏幕分辨率。为了能在不同的分辨率下使项目中所包含的图像都能得到恰当的展示效果。可以利用picture标签和srcset属性提供图像的多个变体。
<img src='photo.jpg' srcset='[email protected],[email protected]' alt='photo'/>
除了ie和其他较低版本的浏览器不支持,目前主流的大部分浏览器都已支持img标签的srcset属性。在srcset属性中设置多种分辨率的图像文件以及使用条件,浏览器在请求之前便会先对此进行解析,只选择最合适的图像文件进行下载,如果浏览器不支持,务必在src属性中包含必要的默认图片。
使用picture标签则会在多图像文件选择时,获得更多的控制维度,比如屏幕方向、设备大小、屏幕分辨率等。
<picture>
<source media="(min-width:800px)" srcset="photo.jpg,[email protected]"/>
<source media="(min-width:450px)" srcset="photo.jpg,[email protected]"/>
<img src='photo.jpg'/>
</picture>
由于picture标签也是加入标准不久的元素标签,所以在使用过程中,同样应考虑兼容问题。
无损和有损压缩
压缩时降低源文件大小的有效方式,对js代码或网页的一些脚本文件而言,压缩掉的内容是一些多余的空格以及不影响执行的注释,其目的是在不损坏正常执行的情况下,尽量缩小源文件的大小。对图像文件而言,由于人眼对不同颜色的敏感度存在差异,所以便可通过减少对某种颜色的编码位数来减少文件大小,甚至还可以损失部分源文件信息,以达到近似效果,使得压缩后的文件尺寸更小。
对于图像压缩,应该是使用有损压缩还是无损压缩,可以简单分为两步进行。
- 确定业务所需要展示图像的颜色阶数、图像显示的分辨率以及清晰程度,当锚定了这几个参数的基准后,如果获取的图像源文件的相应参数指标过高,便可适当进行有损压缩,通过降低源文件图像质量的方法来降低图像文件大小。
如果业务所要求的图像质量较高,便可跳过有损压缩,直接进入第二步无损压缩。所以是否要进行有损压缩,其实是在理解了业务需求后的一个可选选项,而非必要的。 - 当确定了展示图像的质量后,便可利用无损压缩技术尽可能降低图像大小。无损压缩是应当完成的工作环节。因此最好能通过一套完整的工程方案,自动化执行来避免繁琐的人工重复工作。
CSS Sprite
雪碧图,通过将多张小图标拼接成一张大图,有效地减少http请求数量以达到加速显示内容的技术。
通常对于雪碧图的使用场景应当满足以下条件:首先这些图标不会随用户信息的变化而变化,它们属于网站通用的静态图标;同时单张图标体积尽量小,这样经过拼接后其性能的提升才会比较乐观;若加载量比较大则效果会更好。但是不建议将较大的图片拼接成雪碧图,因为大图拼接后的单个文件体积会非常大,这样占用网络带宽的增加与请求完成所耗费时间的延长,会完全淹没通过减少http请求次数所带来的性能提升。
雪碧图的使用方式十分简单:通过css的background-image属性引入雪碧图的url后,再使用background-position定位所需要的单个图标再雪碧图上的起始位置,配合width和height属性来锁定具体图标的尺寸。
.sprite-sheet{
background-image:url(https://xxxxx);
background-size: 24px 600px
}
.icon-1 .sprite-sheet{
background-position: 0 0;
height:24px;
width:24px;
}
.icon-2 .sprite-sheet{
background-position: 0 -24px;
height:24px;
width:24px;
}
使用雪碧图来提升小图标加载性能的历史由来已久。在http1.x环境下,它确实能够减少相应的http请求,但需要注意当部分图标变更时,会导致已经加载的雪碧图缓存失效。同时在http2中,最好的方式应该是加载单张图像文件,因为可以在一个http连接上发起多次请求,所以对于是否使用此方法,需要考虑具体的使用环境和网络设置。
图像格式选择建议
首先明确告诉读者:不存在适用于任何场景且性能最优的图像使用方式。所以作为开发者,想要网站性能在图像方面达到最优,如何根据业务场景选择合适的文件格式尤其重要,图像文件的使用策略如下图所示:
注意:使用webp格式的图像需要考虑到浏览器的兼容性。通常的处理思路分为两种:一种是在前端处理浏览器兼容性的判断,可以通过浏览器的全局属性window.navigator.userAgent获取版本信息,再根据兼容支持情况,选择是否请求webp图像格式的资源;也可以使用<picture/>标签来选择显示的图像格式。
<picture>
<source srcset="photo.webp" type="image/webp"/>
<img src='photo.jpg'/>
</picture>
除此之外,位图对于不同缩放比的响应式场景,建议提供多张不同尺寸的图像,让浏览器根据具体场景进行请求调用。
参考文章:https://blog.csdn.net/qq_42691298/article/details/128485051
Web字体
使用web字体有多种优点:增强网站的设计感、可读性,同时还能搜索和选取所表示的文本内容,且不受屏幕尺寸与分辨率的影响,能提供一致的视觉体验。除此之外,由于每个字型都是特定的矢量图标,所以可以将项目中用到的矢量图打包到一个web字体文件中使用,以节省对图标资源的http请求次数,这样做类似雪碧图优化目的。
-
字体的使用
目前网络上常用的字体格式有:EOT、TTF、WOFF与WOFF2,由于存在兼容问题,并没有哪一种字体能够适用所有浏览器,所以在实际使用中,网站开发者会声明提供字体的多种文件格式,来达到一致性的体验效果。
在web项目中,一般会先通过@font-face声明使用的字体系列:@font-face { font-family: 'myFont'; src: url('./my-font.ttf') format('truetype'); src: url('./my-font.woff') format('woff'), url('./my-font.woff2') format('woff2'); font-weight: 600; font-style: normal; } .my-font { font-family: 'myFont'; color: red; }
在上述代码中通过src字段的属性值,可以指定字体资源的位置,并且该属性值还可以提供一个用逗号分隔的列表,列表中不同字体文件格式的资源顺序同样重要,浏览器将选取其所支持的第一个格式资源。如果希望较新的woff2格式被使用,则应当将woff2声明在woff之上。
-
子集内嵌
如果将所有字型都打包成一个文件来请求使用,不免就会存在许多根本用不到的字型信息浪费带宽。相较于拉丁文字体而言,包含中文字符的字体文件的大小会格外突出。可以使用unicode-range属性定义所使用的字体子集。它支持三种形式:单一取值(如U+233)、范围取值(如U+233-2ff)、通配符范围(如U+2??),取值的含义是字体集文件中的代码索引点:@font-face { font-family: 'myFont'; src: url('./my-font.ttf') format('truetype'); src: url('./my-font.woff') format('woff'), url('./my-font.woff2') format('woff2'); unicode-range:U+100-3ff,U+f??