浏览器IMG图片原生懒加载loading=”lazy”实践指南

这篇文章发布于 2019年09月30日,星期一,00:20,归类于 HTML相关, JS实例。 阅读 72983 次, 今日 54 次 31 条评论

 

原生懒加载

一、Lazy loading Chrome 76支持啦

年初就听说Chrome浏览器的IMG图片和IFRAME框架会支持原生懒加载特性,使用loading="lazy"语法。

盼星星盼月亮,终于,兼容性表中的格子绿啦,绿色真好,Chrome76支持!

图片原生懒加载兼容性

一看自己的浏览器,嘿嘿嘿,已经升级到最近版本,兼容性足够了,可以玩起来啦:

我Chrome浏览器版本

二、懒加载特性的研究

如果你想要让一张图片在靠近浏览器视窗的时候才加载,下面代码就可以了:

<img src="./example.jpg" loading="lazy" alt="zhangxinxu">

无需任何其他的JavaScript代码就可以实现懒加载功能。

眼见为实,您可以狠狠地点击这里:图片原生懒加载lazy loading演示demo

demo页面共有30张 180*180的垂直展示的图片。

我们打开控制台,刷新页面,可以看到加载了有17张图片,剩下的13张没有加载。

加载了17个资源

居然加载了17张图片,这个数量远远超出了自己的预估!

因为按照demo页面现在的布局,一屏只能显示4张图片,现在一口气加载了17张,难道是加载4屏高度以内的图片素材?

于是我把页面屏幕显示高度变小,再刷新看看,结果如下:

加载了13张图片素材

可见加载素材的个数确实和屏幕的可用高度有关,但是并不是按照屏幕高度比例来计算的,迷茫了,没办法,看看规范文档,里面是怎么说的,然而并没有找到相关信息,很可能加载的细节是浏览器厂商自己决定的。

因此,可以得到第一个结论:

1. Lazy loading加载数量与屏幕高度有关,高度越小加载数量越少,但并不是线性关系。

疑问:与网速有关?

难道与网速有关,为了快速滚动滚动条的时候有更好的体验,而不会出现空白占位?

我又把网速调慢测试了下,结果发现果然有关!

在慢网速环境下,加载图片数量更多了,为了避免误差,我反复对比测试,证实了这个结论:

2. Lazy loading加载数量与网速有关,网速越慢,加载数量越多,但并不是线性关系。

例如,在默认状态下,图片加载数量稳定在16个,但是,如果是Fast 3G,则加载数量稳定在21个:

21个图片资源加载

如果是Slow 3G,则加载数量稳定在29个:

Slow 3G加载29个图片资源

用户行为与加载测试

当我们滚动屏幕的时候,没有加载的图片开始按照位置依次加载了,没有任何等待和缓冲。

滚动后加载的素材

因此可以得到结论:

3. 滚动即会触发图片懒加载,不会说滚动一屏后再去加载。

另外,测试的时候还发现另外一个现象:

4. 窗口resize尺寸变化也会触发图片懒加载,当屏幕高度从小变大的时候。

例如我们把控制台从下方变到右侧,此时浏览器高度图片变高,会发现又多了几个图片请求:

浏览器控制台位置变化

resize与滚动请求

滚动记忆与跳过加载?

浏览器普通刷新的时候会记住上一次滚动的位置,如果页面之前滚动位置是在很下面,这个时候页面刷新,那么开头那些图片会不会不加载呢?

我测试了下,结果果不其然,开始的图片并不会加载,只会加载下面的图片,看来浏览器还是挺聪明的。

滚动刷新加载后面的图片

5. 根据滚动位置不同,Lazy loading会忽略头尾的图片请求。

三、语法和参数

HTML loading属性支持的值除了'lazy'还有下面这几个:

lazy
图片或框架懒加载,也就是元素资源快要被看到的时候加载。
eager
图片或框架无视一切进行加载。
auto
默认值。图片或框架基于浏览器自己的策略进行加载。

如果HTMLImageElement或者HTMLIFrameElement元素没有显式地设置loading属性或者loading属性的值不合法,则都被当作'auto'处理。

四、与JS有关的实践指南

1. 如何判断当前浏览器是否支持loading=”lazy”?

下面三种方法都可以:

var isSupportLoading = 'loading' in document.createElement('img');

或者:

var isSupportLoading = 'loading' in new Image();

或者:

var isSupportLoading = 'loading' in HTMLImageElement.prototype;

2. 如何获取loading属性值

假设<img>元素的DOM变量名是img,则该图片元素的loading属性值直接下面语法就可以获取了:

var attrLoading = img.loading;

loading属性值获取结果

如果浏览器并不支持原生的loading懒加载,则会返回undefined,例如在Firefox浏览器下:

loading属性无法获取

3. loading自定义扩展并不会覆盖

例如:

HTMLElement.prototype.loading = function () {};
img = document.querySelector('[loading]');
img.loading;

我们在HTMLElement原型上扩展一个名为loading的函数,并不会影响图片元素原生的loading属性。

Chrome下图片的loading属性还在

但是,对于不支持的浏览器,例如Firefox,则明显受到了影响:

Firefox浏览器下的图片loading

4. 如何兼容不支持的浏览器?Polyfill?

GitHub上有个项目用来兼容原生的懒加载loading属性的,项目地址:https://github.com/mfranzke/loading-attribute-polyfill

我看了下原理,是需要把图片HTML代码放在<noscript>标签中:

<noscript class="loading-lazy">
    <img
        src="example.jpg"
        loading="lazy"
        alt="zhangxinxu"
        width="250"
        height="150"
    />
</noscript>

我头上立马出现了一连串的问号,恕我愚钝,这是个锤子效果的polyfill,无JavaScript特性下表现确实符合规范,但是有JavaScript的时候,你这串代码基本上就没有实用价值,因为图片素材本身是占据尺寸大小的,与布局密切相关的,放在<noscript>标签中,占据宽高尺寸都是0,体验一团糟,完全不能接受。

唯一可行方案是HTML代码输出的时候,根据浏览器(最好JS对象判断)输出不同的HTML代码,例如支持native loading的HTML这样:

<img src="example.jpg" loading="lazy" alt="zhangxinxu" width="250" height="150">

不支持的这样:

<img data-src="example.jpg" loading="lazy" alt="zhangxinxu" width="250" height="150">

然后再使用传统的JavaScript懒加载滚动加载实现即可。

五、研究与实践结果总结

最后,总结下,原生懒加载的5个行为特性:

  1. Lazy loading加载数量与屏幕高度有关,高度越小加载数量越少,但并不是线性关系。
  2. Lazy loading加载数量与网速有关,网速越慢,加载数量越多,但并不是线性关系。
  3. Lazy loading加载没有缓冲,滚动即会触发新的图片资源加载。
  4. Lazy loading加载在窗口resize尺寸变化时候也会触发,例如屏幕高度从小变大的时候。
  5. Lazy loading加载也有可能会先加载后面的图片资源,例如页面加载时滚动高度很高的时候。

与JavaScript有关的几个行为特征:

  1. 判断浏览器是否支持原生loading,最好使用'loading' in XXX判断。
  2. 获取loading属性值可以直接img.loading;
  3. 原生loading不可写,例如HTMLImageElement.prototype.loading会报错Illegal invocation。
  4. Polyfill就是场梦,只能等浏览器支持。

以上~

还有1分钟24:00,嘿嘿嘿。

节前最后一天,赶一篇还算前沿的研究小文,以此来祝愿大家国庆节过得开心快乐,快乐开心。

对了,我的新书《CSS选择器世界》上市了,国庆回来记得买一本支持下,恩……不对,买一本让自己CSS技术提高下。

(本篇完)

分享到:


发表评论(目前31 条评论)

  1. L.Rain说道:

    值现在只有两个了吧,没有auto了

  2. Jkkoi说道:

    支持占位图片嘛

  3. zzkkui说道:

    我也试了下,将img高度固定,或者img的父元素高固定,是有效果的,不过试了下也是加载了三屏的图片(我一张图片的父元素设置了一屏高度)

  4. tommy ki说道:

    看了这篇文章 ,动手试了下,不知道哪出了问题,没有懒加载迹象(黑人问号)
    贴上地址:
    stackblitz.com/edit/angular-ivy-uzs3gh?file=src%2Fapp%2Fapp.component.html

  5. Alex Liu说道:

    前陣子 Chrome 的 機制有大幅度的修改。

    以 4G 網路來說,原本距離螢幕約 3000px 就會載入,現在則調整到 1250px 左右;而 3G 的部分則從 4000px 修改到 2500px。

    這項更新從過去的 79 版到現在最新的 85 都涵蓋在內。

    詳細內容可以參考這一篇:https://web.dev/native-lazy-loading/#improved-data-savings-and-distance-from-viewport-thresholds

  6. 洗衣粉说道:

    我的chrome 80版本的怎么还是一次性加载30个图片啊?

  7. 泽泽说道:


    像这样把展示图片怎么弄成懒加载,头大了

  8. zwkkwz1说道:

    只有图片高度确定时这功能才有用

    • 深蓝说道:

      不是,我自己测试没有写任何与高度相关的属性或者style,也会触发加载的。不过加载数量确实很迷糊,而不是控制图片元素到达视口才会加载。

  9. zwkkwz1说道:

    如果一行几张图片,宽度变化的时候也会触发图片加载。
    这功能太棒了。应该是最好的加载体验。页面滚动也不容易出现需要等待图片加载的情况(滚动速度快网速慢的时候需要等待图片加载那是不可避免的)。

  10. RisingSun说道:

    浏览器越来越强大了,不过感觉还是没第三方库更“智能“”

  11. jinsong5说道:

    张老师,我用手机微信打开的dwmo,看不到图片,只有转圈圈的loading图,是demo没有做普通浏览器的兼容吗

  12. 咧嘴笑说道:

    佩服这种钻研精神,能一直保持着这么强大的学习动力,好赞

  13. MO说道:

    能理解这个api的想法,眼睛可见的图片优先加载,网络良好时尽量延迟加载,网络不好时尽量加载,尽量让体验好起来,而不是一个劲的延迟加载,体验至上~
    可惜属于新特性,还不到尽情使用的时候啊~

  14. XboxYan说道:

    之前也试过了,加载有点诡异的感觉

  15. saber酱说道:

    想不到浏览器原生支持图片懒加载了,很好!

  16. fehey说道:

    「2. Lazy loading加载数量与网速有关,网速越慢,加载数量越多,但并不是线性关系。」

    网速越慢,加载越多,感觉不太符合常理?按理说,网速越慢,不应该少加载一点吗?

    求解惑

  17. zhangolve说道:

    不错,不错,研究的精神很让人学习。
    国庆节快乐。