前端性能优化——图片篇
前言
在一些官网或者电商项目中,往往存在大量的图片,如 banner 广告图,菜单导航图,商家列表头图等。图片过多以及图片体积过大往往会影响页面加载速度,造成不良的用户体验,所以对图片进行优化势在必行。
一、图片压缩
F12打开控制台,找到 Network,点击 Img,我们可以看到当前网页所有的图片资源;点击Size,对图片进行从大到小的排序,我们可以对超过100kB的图片进行压缩。
压缩地址: 在线压缩图像
注意:选择批量压缩会更方便,压缩之后需要进行检查,若压缩过后的图片仍然大于100kB,需要进行二次压缩。
页面效果:
二、使用雪碧图
把诸多小图片合成一张大图,利用 backround-position 属性值来确定图片呈现的位置,可以有效的较少请求个数,而且,而不影响开发体验,使用构建插件可以做到对开发者透明。适用于页面图片多且丰富的场景。
.img-tab-top a.on{
background: url("../ossweb-img/spr.png") no-repeat;
background-position: -566px -150px;
}
.arr-right{
background: url("../ossweb-img/spr.png") no-repeat -863px -150px;
position: absolute;
width: 31px;
height: 30px;
}
三、图片懒加载
在一些图片比较多的网站图片是非常多的,如果我们在打开网页的一瞬间就把网站的所有图片加载出来,很有可能造成卡顿和白屏的现象,用户体验变得极其的差。
因为图片真的很多,一瞬间就把网站的所有图片加载出来浏览器短时间内根本处理不完,但是我们打开网站的那一瞬间仅仅只能看到视口内的图片。只去加载视口内的图片,就是懒加载技术。
懒加载的原理其实很简单,就是预先将图片真实的 src 放在我们自定义的属性里面(比如:data-src),当图片出现在了我们的视口范围之内的时候,再把 data-src 赋值给 src 属性,完成图片加载。
/**
* 懒加载
* @description 可加载`<img>`、`<video>`、`<audio>`等一些引用资源路径的标签
* @param {object} params 传参对象
* @param {string?} params.lazyAttr 自定义加载的属性(可选)
* @param {"src"|"background"} params.loadType 加载的类型(默认为`src`)
* @param {string?} params.errorPath 加载失败时显示的资源路径,仅在`loadType`设置为`src`中可用(可选)
*/
function lazyLoad(params) {
const attr = params.lazyAttr || "lazy";
const type = params.loadType || "src";
/** 更新整个文档的懒加载节点 */
function update() {
const els = document.querySelectorAll(`[${attr}]`);
for (let i = 0; i < els.length; i++) {
const el = els[i];
observer.observe(el);
}
}
/**
* 加载图片
* @param {HTMLImageElement} el 图片节点
*/
function loadImage(el) {
const cache = el.src; // 缓存当前`src`加载失败时候用
el.src = el.getAttribute(attr);
el.onerror = function () {
el.src = params.errorPath || cache;
}
}
/**
* 加载单个节点
* @param {HTMLElement} el
*/
function loadElement(el) {
switch (type) {
case "src":
loadImage(el);
break;
case "background":
el.style.backgroundImage = `url(${el.getAttribute(attr)})`;
break;
}
el.removeAttribute(attr);
observer.unobserve(el);
}
/**
* 监听器
* [MDN说明](https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver)
*/
const observer = new IntersectionObserver(function (entries) {
for (let i = 0; i < entries.length; i++) {
const item = entries[i];
if (item.isIntersecting) {
loadElement(item.target);
}
}
})
update();
return {
observer,
update
}
}
四、图片预加载
图片预加载,是指在一些需要展示大量图片的网站,将图片提前加载到本地缓存中,从而提升用户体验。
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; }
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);
五、渐进式图片
渐进式图片的意思是在高画质图像加载完之前会先显示低画质版本。低画质版本由于画质低、压缩率高,尺寸很小,加载很快。在两者之间我们也可以根据需要显示不同画质的版本。
六、用img标签代替background-url的属性
在做移动端项目的时候,出现了弹窗弹出但是背景图没有显示的问题:
首先是看了一下背景图,发现图片在4M左右,所以先对背景图进行了压缩,但是在微信开发者程序测试,发现无效;
然后将 bgc 的方式更换成了 img 的方式:
发现弹框弹出正常:
总结
请参考: 前端性能优化——图片篇