本文收录于github github.com/Michael-lzg...
在电商项目中,经常会出现大量的图片,比如Banner广告图片、菜单导航图片、美团等商品详情页头图片等。图片过多、过大往往会影响页面加载速度,导致页面加载速度变慢。用户体验不好,所以图片优化势在必行。
我们先看一下页面启动时加载的图片信息。
如图所示,页面启动时会加载几十张(甚至更多)图片css加载字体,而且这些图片请求几乎是并发的。 在Chrome浏览器中,支持的最大并发请求数是有限的,其他请求会进入队列等待或原地踏步,直到上一轮请求完成后发出新的请求。 因此,相当一部分图片资源请求需要排队等待,过多的图片肯定会影响页面的加载和显示。
选择合适的图像格式JPEG
JPEG 是由联合图像专家组开发的图片。 它最大的特点就是有损压缩。 这种高效的压缩算法使其成为一种非常轻量级的图像格式。 另一方面,尽管被称为“有损”压缩,JPG的压缩方式一直是一种高质量的压缩方式:当我们将图像体积压缩到原始体积的50%以下时,JPG仍然可以保持60% 。 % 质量。 另外,JPG格式以24位存储单张图像,最多可以呈现1600万种颜色,足以满足大多数场景下的色调要求,这就决定了压缩前后的质量损失不容易被压缩。我们人类的眼睛。 意识到的。
优势
使用场景
巴布亚新几内亚
PNG(Portable Network Graphics Format)是W3C开发的图片格式,是一种无损压缩的高保真图片格式。 它支持8位和24位,这里是二进制数的位数。 根据我们后知识中提到的对应关系,8位PNG最多支持256种颜色,而24位PNG可以显示大约1600万种颜色。
PNG图像比JPEG有更强的色调表现力,腰线的处理更饱满,对透明度有很好的支持。 它填补了我们上面谈到的JPEG的局限性,唯一的缺点是体积太大。
应用场景
动图
GIF 是一种 8 位无损图像格式,最多支持 256 种颜色。 这一限制使得 GIF 格式无法显示多色或照片图像。
优势
应用场景
网络P
WebP 是一种提供有损压缩和无损压缩(可逆压缩)的图像文件格式,源自图像编码格式 VP8。 像JPEG一样,它对于细节图片来说很方便,像PNG一样,它支持透明度,像GIF一样,它可以显示动态图片,并且它结合了多种图片文件格式的优点。
WebP 最初于 2010 年发布,目标是减小文件大小,但实现与 JPEG 相同的图像质量,并希望减少通过网络发送图像文件所需的时间。 根据谷歌早期的测试,WebP 的无损压缩与互联网上找到的 PNG 文件相比,文件大小减少了 45%。 即使使用 pngcrush 和 PNGOUT 处理 PNG 文件,WebP 仍然可以将文件大小减少 28%。
虽然webP有很多优点,但它并不能完全取代JPEG和PNG,因为浏览器对WebP的支持并不普遍。 特别是移动端IOS系统基本不支持。
图像压缩
我们再看一下一张图片的加载过程:
图片过多、图片尺寸过大往往会影响页面加载速度,导致用户体验不佳。 有的图片达到几百kB,甚至2M(这锅需要运算来背,非得上传高清大图吗?),直接导致Loading时间过长。 因此,对于尺寸过大的图片,可以适当压缩图片的尺寸,同时将图片保持在可接受的清晰度范围内。
图像压缩分为有损压缩和无损压缩。
有损压缩
有损压缩是指在压缩文件大小的过程中,丢失了图片的部分信息,即提高了图片的质量(即图片被压缩),并且这些损失是不可逆的。 常见的有损压缩方法是按照一定的算法将相邻像素进行组合。 压缩算法并不是对图片的所有数据进行编码和压缩,而是在压缩时去除图片中人眼难以识别的细节。 因此,有损压缩可以在相同图像质量的情况下大幅增加图像的体积。 例如,jpg格式的图片使用有损压缩。
无损压缩
无损压缩是指在不损失图片质量的情况下压缩图片的过程。 我们可以随时从无损压缩图片中恢复原始信息。 压缩算法对图片的所有数据进行编码压缩,可以在保证图片质量的同时增加图片的体积。 例如,png和gif使用无损压缩。
以下是各种图像格式的压缩类型
工具压缩 webpack 压缩
工程项目可以在webpack中配置image-webpack-loader进行图像压缩
安装依赖项
npm install --save-dev image-webpack-loader
配置网络包
module.exports = {
...
module: {
rules: [
{
test: /.(png|jpe?g|gif|svg)(?.*)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[hash:7].[ext]'
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 50,
},
optipng: {
enabled: true,
},
pngquant: {
quality: [0.5, 0.65],
speed: 4,
},
gifsicle: {
interlaced: false,
},
webp: { // 不支持WEBP就不要写这一项
quality: 75
},
},
},
],
},
],
},
}
至于是否使用插件手动压缩,那就见仁见智了,因为有些UI和产品会说压缩后的疗效图不是自己想要的。
使用精灵
雪碧图,CSS Sprites,国内也叫CSS sprites,是一种CSS图像合成技术,主要用于小图片显示。
浏览器请求资源时,对同源域名请求资源有最大并发限制。 Chrome是6。例如,如果您的页面上有10张同一个CDN域名的小图片,则需要发起10个请求来拉取它们,分两批并发。 第一个并发请求返回后,发起第二个并发请求。 如果将10张小图合并为一张大图,那么只需一次请求就可以拉取10张小图的资源。 减轻服务器压力,减少并发,减少请求数。
优势
将很多小图片组合成一张大图片,利用background-position属性值来确定图片的位置,可以有效减少请求次数,并且在不影响开发体验的情况下,创建插件的使用可以是透明的给开发商。 适合页面图片较多且丰富的场景。
缺点
生成的图片尺寸较大,减少请求数量也减少了图片尺寸,不合理的分割将不利于并行加载。
复合精灵
在webpack中,有一个对应的插件提供了手动合成精灵图像的功能但可以手动生成对应的样式文件——webpack-spritesmith,用法如下
var path = require('path')
var SpritesmithPlugin = require('webpack-spritesmith')
module.exports = {
// ...
plugins: [
new SpritesmithPlugin({
src: {
cwd: path.resolve(__dirname, 'src/ico'),
glob: '*.png',
},
target: {
image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'),
css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl'),
},
apiOptions: {
cssImageRef: '~sprite.png',
},
}),
],
}
通过前面的配置,就可以将src/ico目录下的所有png文件合成为精灵图片,并输出到对应的目录中。 同时可以生成相应的样式文件。 样式文件的句型将根据您配置的样式文件后缀动态生成。
使用图标字体
iconfont(字体图标),以字体的形式显示图标,多用于渲染图标、简单图形、特殊字体等。
优势
推荐使用阿里的字体图标库:iconfont
使用base64格式
原理:将图像转换为base64编码的字符串内联到页面或css中。
优势
但需要注意的是,如果图像较大且图像的色调层次比较丰富,这些方法就不适合使用,因为图像的base64编码字符串非常大,这会明显减小图像的大小HTML 页面,从而影响加载速度。
最常见的 base64 化用于 url-loader。
module.exports = {
...
module: {
rules: [
{
test: /.(png|jpe?g|gif|svg)(?.*)?$/,
loader: 'url-loader',
options: {
limit: 10240,
name: utils.assetsPath('img/[name].[hash:7].[ext]'),
}
},
],
},
}
这样可以将项目中大于10kb的图片转换成base64应用到页面中
使用 css 代替图像。
比如要实现装饰效果,如半透明、边框、圆角、阴影、渐变等,在目前主流浏览器中都可以用CSS来实现,这样可以降低对图片的要求,达到优化的目的。
缺点
使用CDN镜像
CDN的全称是Content Delivery Network,即内容分发网络。 CDN是建立在互联网上的内容分发网络。 依托部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,用户可以就近获取所需内容,减少网络串扰,提高用户访问响应率和命中率。 CDN的关键技术主要包括内容存储和分发技术。
举一个简单的例子:
以前,你只能去火车站买火车票。 后来我们买火车票的时候,就可以在楼下的火车票销售点购买。
基本的
CDN的基本原理是广泛采用各种缓存服务器,将此类缓存服务器分布到用户访问相对集中的区域或网络,在用户访问网站时,利用全局负载技术将用户引导到最近的工作正常站点。 在缓存服务器上,缓存服务器直接响应用户请求。
基本思想
CND的基本思想是尽可能避开互联网上可能影响数据传输速率和稳定性的困难和链路,从而使内容传输更快、更稳定。 通过在网络各处放置节点服务器,在现有互联网的基础上形成一层智能虚拟网络,CDN系统可以实时根据网络流量和各节点的连接情况、负载状况以及到用户的距离根据时间、响应时间等综合信息,将用户的请求重定向到距离用户最近的服务节点。 其目的是使用户能够就近获取所需内容,解决Internet网络拥塞情况,提高用户访问网站的响应率。
CDN 的优点
图片延迟加载
延迟加载是网页性能优化的一种形式,可以极大地改善用户体验。 图像仍然是网页性能的主要原因,现在图像超过几兆字节的情况并不罕见。 如果每次进入页面时都请求所有的图片资源,那么用户可能会在图片加载完毕后很久就离开。 所以进入页面时,只请求可见区域的图片资源。
总结起来就是:
原则
图片延迟加载的原理是暂时不设置图片的src属性,而是隐藏图片的url,比如先写在data-src中,然后将图片的真实url放入当前图片在上方可见区域后添加src属性,从而实现图片的延迟加载。
function lazyload() {
let viewHeight = document.body.clientHeight //获取可视区高度
let imgs = document.querySelectorAll('img[data-src]')
imgs.forEach((item, index) => {
if (item.dataset.src === '') return
// 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置
let rect = item.getBoundingClientRect()
if (rect.bottom >= 0 && rect.top < viewHeight) {
item.src = item.dataset.src
item.removeAttribute('data-src')
}
})
}
// 可以使用节流优化一下
window.addEventListener('scroll', lazyload)
通过前面反例的实现,我们需要监听滚动事件来实现延迟加载。 虽然我们可以通过函数节流来阻止高频执行函数,但是我们仍然需要估计scrollTop、offsetHeight等属性。 有吗? 一个简单的方法,不需要估计这个属性,答案是肯定的---IntersectionObserver
const imgs = document.querySelectorAll('img[data-src]')
const config = {
rootMargin: '0px',
threshold: 0,
}
let observer = new IntersectionObserver((entries, self) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
let img = entry.target
let src = img.dataset.src
if (src) {
img.src = src
img.removeAttribute('data-src')
}
// 解除观察
self.unobserve(entry.target)
}
})
}, config)
imgs.forEach((image) => {
observer.observe(image)
})
图片预加载
图片预加载是指在一些需要显示大量图片的网站上,提前将图片加载到本地缓存中,从而提高用户体验。
常用的方法有两种,一种是隐藏在css背景的url属性上,另一种是通过javascript的Image对象设置实例对象的src属性,实现图像的预加载。
1.用CSS和JavaScript实现预加载
#preload-01 {
background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px;
}
#preload-02 {
background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px;
}
#preload-03 {
background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px;
}
通过 CSS 背景属性在屏幕外背景上预加载图像。 当网页上的其他位置调用图像时,浏览器会在渲染期间使用预加载(缓存)的图像。 这种方法实际上是有效的css加载字体,但仍有改进的空间。 使用此方法加载的图像将与页面上的其他内容一起加载,从而增加页面的整体加载时间。
为了解决这个问题,我们减少了一些 JavaScript 代码来延迟预加载时间,直到页面加载完毕。
function preloader() {
if (document.getElementById) {
document.getElementById('preload-01').style.background =
'url(http://domain.tld/image-01.png) no-repeat -9999px -9999px'
document.getElementById('preload-02').style.background =
'url(http://domain.tld/image-02.png) no-repeat -9999px -9999px'
document.getElementById('preload-03').style.background =
'url(http://domain.tld/image-03.png) no-repeat -9999px -9999px'
}
}
function addLoadEvent(func) {
var oldonload = window.onload
if (typeof window.onload != 'function') {
window.onload = func
} else {
window.onload = function () {
if (oldonload) {
oldonload()
}
func()
}
}
}
addLoadEvent(preloader)
2.使用JavaScript实现预加载
function preloader() {
if (document.images) {
var img1 = new Image()
var img2 = new Image()
var img3 = new Image()
img1.src = 'http://domain.tld/path/to/image-001.gif'
img2.src = 'http://domain.tld/path/to/image-002.gif'
img3.src = 'http://domain.tld/path/to/image-003.gif'
}
}
function addLoadEvent(func) {
var oldonload = window.onload
if (typeof window.onload != 'function') {
window.onload = func
} else {
window.onload = function () {
if (oldonload) {
oldonload()
}
func()
}
}
}
addLoadEvent(preloader)
响应式图像加载
什么是响应式图像加载? 其实就是在不同码率的设备上显示不同规格的图片,避免资源浪费。
常用的方法是CSS3媒体查询(media query)。
@media screen and (min-width: 1200px) {
img {
background-image: url('1.png');
}
}
@media screen and (min-width: 992px) {
img {
background-image: url('2.png');
}
}
@media screen and (min-width: 768px) {
img {
background-image: url('3.png');
}
}
@media screen and (min-width: 480px) {
img {
background-image: url('4.png');
}
}
另外,HTML5的图片属性可以用于响应式处理。 方法如下:
创建图片标签。 放置多个source标签来指定不同的图像文件名,然后根据不同的条件加载。添加一个fallback元素
<picture>
<source srcset="src/img/l.png" media="(min-width: 1200px)" />
<source srcset="src/img/2.png" media="(min-width: 992px)" />
<source srcset="src/img/4.png" media="(min-width: 768px)" />
<img src="src/img/4.png" />
</picture>
需要注意的是,很多浏览器还不支持图片标签,所以使用时需要注意。
渐进图像
渐进式图像意味着在加载更高质量的图像之前显示较低质量的版本。 低质量版本由于其低帧率、高压缩率和小尺寸而加载速度快。 在两者之间我们还可以根据需要显示不同音质的版本。
渐进式图像给用户的印象是图像加载速度更快。 用户不用盯着空白区域等待图像加载,而是可以看到图像变得越来越清晰,这对用户体验也很友好。
骨架屏技术也是类似的原理。
综上所述,选择合适的图片格式,对大图进行压缩,可以从症结上解决大截图加载慢的问题。 使用sprite、iconfont、base64、css等代替图片,可以减少图片的http请求,提高页面加载速度。 使用CDN图片可以达到分流的疗效,减轻服务凭证的压力。 图片懒加载、预加载、渐进式图片等可以不同程度减少死区时间,提升产品体验。推荐文章
从头开始构建后端 cli 脚手架并将其发布到 npm
你必须知道的webpack插件原理剖析
Webpack的异步加载原理及包传递策略
总结18个webpack插件,总有你想要的!
从头开始创建类似vue-cli的脚手架进行优化
封装一个toast和dialog组件并发布到npm
从头开始构建一个 webpack 项目
总结webpack打包优化的几种方式
vue知识体系中级应用总结
vue知识体系实用总结
总结vue知识体系基本介绍
总结移动H5开发常用方法(干货满满!)