7

现代图片性能优化及体验优化指南 - 懒加载及异步图像解码方案

 1 year ago
source link: https://www.cnblogs.com/coco1s/p/17162742.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文是系列第四篇。系列文章:

图片资源,在我们的业务中可谓是占据了非常大头的一环,尤其是其对带宽的消耗是十分巨大的。

对图片的性能优化及体验优化在今天就显得尤为重要。本文,就将从各个方面阐述,在各种新特性满头飞的今天,我们可以如何尽可能的对我们的图片资源,进行性能优化及体验优化。

懒加载/异步图像解码方案

继续下一个章节。本章节,我们来讨论下图片的懒加载与异步图像解码方案。

图片的懒加载

懒加载是一种网页性能优化的常见方式,它能极大的提升用户体验。到今天,现在一张图片超过几 M 已经是常见事了。如果每次进入页面都需要请求页面上的所有的图片资源,会较大的影响用户体验,对用户的带宽也是一种极大的损耗。

所以,图片懒加载的意义即是,当页面未滚动到相应区域,该区域内的图片资源(网络请求)不会被加载。反之,当页面滚动到相应区域,相关图片资源的请求才会被发起。

在过去,我们通常都是使用 JavaScript 方案进行图片的懒加载。而今天,我们在图片的懒加载实现上,有了更多不一样的选择。

JavaScript 方案实现图片的懒加载

首先,回顾一下过往最常见的,使用 JavaScript 方案实现图片的懒加载。

通过 JavaScript 实现的懒加载,主要是两种方式:

  1. 监听 onscroll 事件,通过 getBoundingClientRect API 获取元素图片距离视口顶部的距离,配合当前可视区域的位置实现图片的懒加载
  2. 通过 HTML5 的 IntersectionObserver API,Intersection Observer(交叉观察器) 配合监听元素的 isIntersecting 属性,判断元素是否在可视区内,能够实现比监听 onscroll 性能更佳的图片懒加载方案

但是,JavaScript 方案的一个劣势在于,不管如何,需要引入一定量的 JavaScript 代码,进行一定量的运算。

到今天,其实我们有更多的其他便捷的方式去实现图片的懒加载。

使用 content-visibility: auto 实现图片内容的延迟渲染

首先,介绍一个非常有用,但是相对较为冷门的属性 -- content-visibility

content-visibility:属性控制一个元素是否渲染其内容,它允许用户代理(浏览器)潜在地省略大量布局和渲染工作,直到需要它为止。

利用 content-visibility 的特性,我们可以实现如果该元素当前不在屏幕上,则不会渲染其后代元素

假设我们有这样一个 DEMO:

<div class="g-wrap">
    // 模块 1
    <div class="paragraph">
        <p>Lorem Start!</p>   
        <img src="https://s1.ax1x.com/2023/02/20/pSX1xMV.png" alt="" />
        <p>Lorem End!</p>  
    </div>
    // 模块 2
    <div class="paragraph">
        <p>Lorem Start!</p>   
        <img src="https://s1.ax1x.com/2023/02/20/pSX1xMV.png" alt="" />
        <p>Lorem End!</p>  
    </div>
    // ... 连续几十个上述类似的结构
</div>

只需要给需要延迟(实时)渲染的元素,设置简单的 CSS 样式:

.paragraph {
    content-visibility: auto;
}

我们来看一下,设置了 content-visibility: auto 与没设置的区别。

如果,不添加上述的 content-visibility: auto 代码,页面的滚动条及滚动效果如下:

d391e2a00ab742b6b67bd7bddb1b1727~tplv-k3u1fbpfcp-watermark.image?

那么,在添加了 content-visibility: auto 之后,注意观察页面的滚动条及滚动效果:

1b9ef35b13434b69aa554a42d9bb9b61~tplv-k3u1fbpfcp-watermark.image?

可以看到滚动条在向下滚动在不断的抽搐,这是由于下面不在可视区域内的内容,一开始是没有被渲染的,在每次滚动的过程中,才逐渐渲染,以此来提升性能。

Codepen Deom -- content-visibility: auto Image Load Demo

content-visibility: auto VS 图片懒加载

当然,其实使用 content-visibility: auto 并不能真正意义上实现图片的懒加载。

这是因为,即便当前页面可视区域外的内容未被渲染,但是图片资源的 HTTP/HTTPS 请求,依然会在页面一开始被触发!

因此,这也得到了一个非常重要的结论:

content-visibility: auto 无法直接替代图片懒加载,设置了 content-visibility: auto 的元素在可视区外只是未被渲染,但是其中的静态资源仍旧会在页面初始化的时候被全部加载。因此,它更像是一个虚拟列表的替代方案。

关于 content-visibility 本文限于篇幅,没有完全展开,但是它是一个非常有意思且对渲染性能有帮助的属性,完整的教程,你可以看我的这篇文章 -- 使用 content-visibility 优化渲染性能

使用 loading=lazy HTML 属性实现图片懒加载

OK,content-visibility 很不错,但是略有瑕疵。但是,我们还有其他方式。

HTML5 新增了一个 loading 属性。

到今天,除了 IE 系列浏览器,目前都支持通过 loading 属性实现延迟加载。此属性可以添加到 <img> 元素中,也可以添加到 <iframe> 元素中。

属性的值为 loading=lazy 会告诉浏览器,如果图像位于可视区时,则立即加载图像,并在用户滚动到它们附近时获取其他图像。

我们可以像是这样使用它:

<img src="xxx.png" loading="lazy">

这样,便可以非常便捷的实现图片的懒加载,省去了添加繁琐的 JavaScript 代码的过程

看看 loading=lazy 到今天(2023-02-26)的兼容性,还是非常不错的:

920752fb77aa42c1824a45a4dc5dfdf4~tplv-k3u1fbpfcp-watermark.image?

使用 decoding=async 实现图片的异步解码

除了 loading=lazy,HTML5 还新增了一个非常有意思的属性增强图片的用户体验。那就是 decoding 属性。

HTMLImageElement 接口的 decoding 属性用于告诉浏览器使用何种方式解析图像数据。

它的可选取值如下:

  • sync: 同步解码图像,保证与其他内容一起显示。
  • async: 异步解码图像,加快显示其他内容。
  • auto: 默认模式,表示不偏好解码模式。由浏览器决定哪种方式更适合用户。

上文其实也提及了,浏览器在进行图片渲染展示的过程中,是需要对图片文件进行解码的,这一个过程快慢与图片格式有关。

而如果我们不希望图片的渲染解码影响页面的其他内容的展示,可以使用 decoding=async 选项,像是这样:

<img src="xxx.png" decoding="async">

这样,浏览器便会异步解码图像,加快显示其他内容。这是图片优化方案中可选的一环。

同样的,我们来看看到今天(2023-02-26),decoding="async" 的兼容性,整体还是非常不错的,作为渐进增强方案使用,是非常好的选择。

515ee054eb374da2b98a3f59dcbf95b6~tplv-k3u1fbpfcp-watermark.image?

实际检验 loading=lazydecoding=async 效果

OK,下面我们制作一个简单的 DEMO,试一下 loading=lazydecoding=async 的效果。

我们准备一个拥有 339 个图片的 HTML 页面,每个图片文件的 src 大小不一。

<div class="g-container">
    <img src="image1.jpeg">
    <img src="image2.jpeg">
    // ... 339 个
</div>

CSS 的设置也很重要,由于是纯图片页面,如果不给图片设置默认高宽,最页面刷新的一瞬间,<img> 元素的高宽都是 0,会导致所有 <img> 元素都在可视区内,所以,我们需要给 <img> 设置一个默认的高宽:

img {
    margin: 8px;
    width: 300px;
    height: 200px;
    object-fit: cover;
}

这样,再不添加 loading=lazydecoding=async 的状态下,看看 Network 的表现:

ab7af983eb8a445a9b1df42cd7481638~tplv-k3u1fbpfcp-watermark.image?

我这里没有模拟弱网环境,网速非常快,可以看到,发送了 339 个图片资源请求,也就是全部的图片资源在页面加载的过程中都请求了,页面 Load 事件完成的时间为 1.28s。

好,我们给所有的图片元素,添加上 loading=lazydecoding=async

<div class="g-container">
    <img src="image1.jpeg" loading="lazy" decoding="async">
    <img src="image2.jpeg" loading="lazy" decoding="async">
    // ... 339 个
</div>

看看效果:

a1997067324645dfba0080aaf4c8008f~tplv-k3u1fbpfcp-watermark.image?

可以看到,这一次只发送了 17 个图片资源请求,页面 Load 事件完成的时间为 26ms。

优化前 优化后
1.28s 26 ms

1.28s 到 26ms,效果是非常明显的,如果是弱网环境,对首屏加载性能的提升,会更为明显

当然,实际我测试的过程也,也单独试过 decoding="async" 的作用,只是由于是纯图片页面,效果不那么明显。感兴趣的同学,可以自行尝试。

在本章节中,我们介绍了不同的方式实现图片的懒加载、延迟渲染、异步解码,它们分别是:

  1. 通过 onscroll 事件与 getBoundingClientRect API 实现图片的懒加载方案
  2. 通过 Intersection Observer(交叉观察器)实现比监听 onscroll 性能更佳的图片懒加载方案
  3. 通过 content-visibility: auto 实现图片资源的延迟渲染
  4. 通过 loading=lazy HTML 属性实现图片懒加载
  5. 通过 decoding=async HTML 属性实现图片的异步解码

当然,本文是现代图片性能优化及体验优化指南的第四篇,后续将给大家带来图片优化的最后一个章节:

  • 可访问性 & 图片资源的容错及错误处理

感兴趣的可以提前关注。

OK,本文到此结束,希望本文对你有所帮助 😃

想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

想 Get 到最有意思的 CSS 资讯,千万不要错过我的 iCSS 公众号 😄 :

image

如果觉得文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK