图片的懒加载
懒加载是一种网页性能优化的常见方式,它能极大的提升用户体验。到今天,现在一张图片超过几 M 已经是常见事了。如果每次进入页面都需要请求页面上的所有的图片资源,会较大的影响用户体验,对用户的带宽也是一种极大的损耗。
所以,图片懒加载的意义即是,当页面未滚动到相应区域,该区域内的图片资源(网络请求)不会被加载。反之,当页面滚动到相应区域,相关图片资源的请求才会被发起。
在过去,我们通常都是使用 JavaScript 方案进行图片的懒加载。而今天,我们在图片的懒加载实现上,有了更多不一样的选择。
使用 content-visibility: auto 实现图片内容的延迟渲染
一个相对较为冷门的属性 – content-visibility
content-visibility:属性控制一个元素是否渲染其内容,它允许用户代理(浏览器)潜在地省略大量布局和渲染工作,直到需要它为止。
利用 content-visibility 的特性,我们可以实现如果该元素当前不在屏幕上,则不会渲染其后代元素。
如果有这个的Dom
<div v-for="item in items" :key="item">
<div class="container-box">
<p>-------------{{ item.id }}-------------</p>
<img :src="item.src" alt=""/>
</div>
</div>
<script>
export default {
data() {
return {
items: [{
id: 0,
src: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg"
},{
id: 1,
src: "https://gtd.alicdn.com/sns_logo/i3/TB1wnBTKFXXXXcQXXXXSutbFXXX.jpg_240x240xz.jpg"
}, {
id: 2,
src: "//www.baidu.com/img/flexible/logo/pc/result.png"
}, {
id: 3,
src: "http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg"
}, {
id: 4,
src: "http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg"
}, {
id: 5,
src: "http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg"
}, {
id: 6,
src: "http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg"
}, {
id: 7,
src: "http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg"
}, {
id: 8,
src: "http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg"
}, {
id: 9,
src: "http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg"
}, {
id: 10,
src: "http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg"
}, {
id: 11,
src: "http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg"
}, {
id: 12,
src: "http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg"
}, {
id: 13,
src: "http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg"
}, {
id: 14,
src: "http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg"
}]
}
}
}
</script>
只需要给需要延迟(实时)渲染的元素,设置简单的 CSS 样式:
.container-box {
content-visibility: auto;
}
但是它有一个缺点:
滚动条在向下滚动在不断的抽搐,这是由于下面不在可视区域内的内容,一开始是没有被渲染的,在每次滚动的过程中,才逐渐渲染,以此来提升性能。
当然,其实使用 content-visibility: auto 并不能真正意义上实现图片的懒加载。
这是因为,即便当前页面可视区域外的内容未被渲染,但是图片资源的 HTTP/HTTPS 请求,依然会在页面一开始被触发!
因此,这也得到了一个非常重要的结论:
content-visibility: auto 无法直接替代图片懒加载,设置了 content-visibility: auto 的元素在可视区外只是未被渲染,但是其中的静态资源仍旧会在页面初始化的时候被全部加载。因此,它更像是一个虚拟列表的替代方案。
参考:https://github.com/chokcoco/iCSS/issues/185
使用 loading=“lazy” 和 decoding=“async” HTML属性实现图片懒加载
content-visibility略有瑕疵,还好我们有其他方式
loading="lazy"
HTML5 新增了一个 loading 属性。
到今天,除了 IE 系列浏览器,目前都支持通过 loading 属性实现延迟加载。此属性可以添加到 < img > 元素中,也可以添加到 < iframe > 元素中。
属性的值为 loading=lazy 会告诉浏览器,如果图像位于可视区时,则立即加载图像,并在用户滚动到它们附近时获取其他图像。
可以这样使用它
<img :src="item.src" alt="" loading="lazy"/>
这样,便可以非常便捷的实现图片的懒加载,省去了添加繁琐的 JavaScript 代码的过程。
loading=lazy 到(2023-02-26)的兼容性,还是非常不错的:
decoding="async
使用 decoding=async 实现图片的异步解码
除了 loading=lazy,HTML5 还新增了一个非常有意思的属性增强图片的用户体验。那就是 decoding 属性。
HTMLImageElement 接口的 decoding 属性用于告诉浏览器使用何种方式解析图像数据。
它的可选取值如下:
sync: 同步解码图像,保证与其他内容一起显示。
async: 异步解码图像,加快显示其他内容。
auto: 默认模式,表示不偏好解码模式。由浏览器决定哪种方式更适合用户。
上文其实也提及了,浏览器在进行图片渲染展示的过程中,是需要对图片文件进行解码的,这一个过程快慢与图片格式有关。
而如果我们不希望图片的渲染解码影响页面的其他内容的展示,可以使用 decoding=async 选项,像是这样:
<img :src="item.src" alt="" loading="lazy" decoding="async"/>
这样,浏览器便会异步解码图像,加快显示其他内容。这是图片优化方案中可选的一环。
同样的,我们来看看到(2023-02-26),decoding=“async” 的兼容性,整体还是非常不错的,作为渐进增强方案使用,是非常好的选择。
性能测试
检验 loading=lazy 与 decoding=async 效果
准备14张图片的页面,每个图片url大小不一
<template>
<div class="container">
<!-- loading="lazy" 懒加载 -->
<div v-for="item in items" :key="item">
<div class="container-box2">
<p>-------------{{ item.id }}-------------</p>
<img :src="item.src" alt="" loading="lazy" decoding="async"/>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: [{
id: 0,
src: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg"
},{
id: 1,
src: "https://gtd.alicdn.com/sns_logo/i3/TB1wnBTKFXXXXcQXXXXSutbFXXX.jpg_240x240xz.jpg"
}, {
id: 2,
src: "//www.baidu.com/img/flexible/logo/pc/result.png"
}, {
id: 3,
src: "http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg"
}, {
id: 4,
src: "http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg"
}, {
id: 5,
src: "http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg"
}, {
id: 6,
src: "http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg"
}, {
id: 7,
src: "http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg"
}, {
id: 8,
src: "http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg"
}, {
id: 9,
src: "http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg"
}, {
id: 10,
src: "http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg"
}, {
id: 11,
src: "http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg"
}, {
id: 12,
src: "http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg"
}, {
id: 13,
src: "http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg"
}, {
id: 14,
src: "http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg"
}]
}
}
}
</script>
CSS 的设置也很重要,由于是纯图片页面,如果不给图片设置默认高宽,最页面刷新的一瞬间, 元素的高宽都是 0,会导致所有 元素都在可视区内,所以,我们需要给 设置一个默认的高宽:
<style>
img {
margin: 8px;
width: 202px;
height: 166px;
object-fit: cover;
}
</style>
首先看看没有添加懒加载的效果(试验环境的网不太好)
可以看到,全部的图片资源在页面加载的过程中都请求了,页面 Load 事件完成的时间为 1.01s
现在我们为他加上 loading="lazy"
与 decoding=async"
首次进入页面仅请求显示在屏幕上的图片,只发送了6个请求,页面 Load 事件完成的时间为 367 ms
当页面滚动时,显示的图片才会继续发送请求
如果在图片量更大的情况下,优化效果会更加显著