图片延迟加载方案

作者: 齐修_qixiuss | 来源:发表于2016-05-05 18:12 被阅读11549次

    图片延迟加载的原理是什么?

    图片延迟加载的原理就是先不设置img的src属性,等合适的时机(比如滚动、滑动等)再把图片真实url放到img的src属性上。
    过多的图片会严重影响网页的加载速度,移动网络下的流量消耗巨大,延迟加载几乎是标配。

    图片延迟加载的使用场景有哪些?

    1. 好奇心日报首页和列表页都有很多固定宽高的图片。
    2. 好奇心日报文章详情页的图片,这些图片需要自适应宽度且保持宽高比(防止页面抖动)。
    固定宽高延迟加载

    这个比较简单,设置好固定宽高,直接使用最简单的延迟加载即可
    淘宝mobile首页的延迟加载有个点做得特别好,滚动结束后只加载当前视窗可见的图片,不会加载滚动超过视窗的图片,也不会加载还没滚动到的视窗图片。

    非固定宽高的延迟加载

    目前大概有两种方案,各有优劣,具体看情况使用:
    第一种方案使用padding-top或者padding-bottom来实现固定宽高比。优点是纯css方案,缺点是html冗余,对输出到第三方不友好

    <div style="padding-top:75%">
        <img data-src="" alt="" class="lazyload">
    <div>
    

    第二种方案在页面初始化阶段利用ratio设置实际宽高值,优点是html干净,对输出到第三方友好,缺点是依赖js,理论上会至少抖动一次

    <img data-src="" alt="" class="lazyload" data-ratio="0.75">
    
    更进一步结合srcset

    除了上面说的延迟加载,我们可以更进一步的引入srcset,通过设置srcset来保证加载最匹配的图片,这样对于一倍屏,二倍屏,三倍屏来说,可以做到不浪费流量且效果最好。

    都有哪些延迟加载开源方案?

    jquery_lazyload

    依赖于jquery

    <img class="lazy" data-original="img/example.jpg" width="640" height="480">
    // 初始化
    $("img.lazy").lazyload();
    

    lazysizes 推荐

    原生js,不依赖于jquery/zepto
    自动监测可能发生变化的lazyload节点,不需要额外初始化
    支持响应式图片srcset
    性能高,改善SEO

    // 引入js文件
    <script src="lazysizes.min.js" async=""></script>
    
    // 非响应式 例子
    <img data-src="image.jpg" class="lazyload" />
    // 响应式 例子,自动计算合适的图片
    <img
        data-sizes="auto"
        data-src="image2.jpg"
        data-srcset="image1.jpg 300w,
        image2.jpg 600w,
        image3.jpg 900w" class="lazyload" />
    // iframe 例子
    <iframe frameborder="0"
        class="lazyload"
        allowfullscreen=""
        data-src="//www.youtube.com/embed/ZfV-aYdU4uE">
    </iframe>
    

    lazyload

    依赖jquery/zepto

    <!-- 直接赋予图片宽高 -->
    <img class="lazy" data-original="img/example.jpg" width="640" height="480">
    <!-- 或:通过css赋予图片宽高 -->
    <style>
        .lazy{width:640px;height:480px;}
    </style>
    <img class="lazy" data-original="img/example.jpg">
    <!-- 或:自适应宽度的图片样式(常用于移动端) -->
    <style>
        .lazy{width:100%;height:0;padding-top:75%;background-size:100%;}
        /* 假设高宽比为 480:640,即75%,并使用背景图的方式将图片铺在padding-top区域内
        (padding的百分比是宽度的百分比而不是高度的,即使是padding-top|padding-bottom) */
    </style>
    <div class="lazy" data-original="img/example.jpg"><div>
    <!-- 请参阅examples/enabled_image_full_width.html -->
    <!-- 初始化 -->
    $(".lazy").lazyload();
    

    微信如何实现延迟加载?

    研究了微信延迟加载的代码,还解决了一个问题,那就是常见于移动端的自适应宽度的延迟加载,即根据情况具体计算宽高。

    // 源码
    <img 
        data-s="300,640" 
        data-type="jpeg" 
        data-src="http://mmbiz.qpic.cn/mmbiz/meG6Vo0MeviaLibiaARRszfMpiaXtejcktPB2fK6uP13R4RS9Y7fHtk5bUd7A9R9zRyZ1nupW8ZVjHwBiaZUa3SkcPg/0?wx_fmt=jpeg" 
        data-ratio="0.8003597122302158" 
        data-w=""  
    />
    
    // 解析后的代码
    <img 
        data-s="300,640" 
        data-type="jpeg" 
        data-src="http://mmbiz.qpic.cn/mmbiz/meG6Vo0MeviaLibiaARRszfMpiaXtejcktPBLbT37dSYzNyhwDTiac0WiaribF0Vt7I3Zd7AG9xXSCUoch61KicnYnfqIw/0?wx_fmt=jpeg" 
        data-ratio="0.8003597122302158" 
        data-w="" 
        src="http://mmbiz.qpic.cn/mmbiz/meG6Vo0MeviaLibiaARRszfMpiaXtejcktPBLbT37dSYzNyhwDTiac0WiaribF0Vt7I3Zd7AG9xXSCUoch61KicnYnfqIw/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&retryload=1" 
        style="width: 414px !important; visibility: visible !important; height: 331.349px !important;" 
    />
    
    /* 其中
    data-s:表示可选的图片尺寸大小
    data-type:表示图片类型
    data-src:表示图片链接
    data-ratio:表示长宽比
    */
    

    由于源码是压缩模式的,做简单的猜测如下:

    1. 对于延迟加载,微信采用的模式和正常的延迟加载的模式类似,即用data-src存储真实的图片链接
    2. 为了解决移动端的自适应宽度的问题,微信存储了长宽比,然后进入页面就计算在不同设备里的真实宽高,并设置在style

    其他问题?

    1. 接入第三方平台的网页怎么处理?
      由于好奇心日报的文章会输出到第三方平台,比如今日头条/一点资讯等平台,这些平台对html都有一定的规范。这时候就需要后台在输出之前对html做一些转换。
      为了简单起见,类似<div class="lazy" data-original="img/example.jpg"><div>的方案不太适合让后台转换,所以微信这种动态计算方法可以借鉴。
    2. 怎么处理响应式图片?
      响应式图片能够根据当前屏幕分辨率加载最匹配的图片,能够因地制宜,详见图片响应式解决方案
    3. 方案有了,回头追加一篇具体实践踩坑的博文

    相关文章

      网友评论

      • 嗷嗷待宰的小粉猪:看了下你的代码,图片一开始是没有宽度的,然后js去获取图片宽度,我这边得到的都是屏幕的宽度,导致图片的高度计算出来很大,图片会被拉伸。这个问题怎么解决呢?
        嗷嗷待宰的小粉猪:就是计算图片高度时,一开始图片还加载,而此时需要计算图片高度,获取img的标签时,拿到的宽度好像是屏幕的宽度,最终导致高度太高而被拉伸。
      • ff8d89794b8a:这种内置data-src的方法与动态加载的形式的优势是什么
        ff8d89794b8a:难道是可以避免回流
      • 海_af41:延迟加载是什么原理, 在DomContentLoaded 就去加载吗, 我看延迟加载的图片 在 loaded事件之前就加载完成了, 这样能提高哪方面的性能

        我说的是首页加载, 不是滚动加载
        齐修_qixiuss:首屏图片加载是否需要延迟根据具体场景决定吧,在哪个时间点延迟也是可以控制的。
        但个人觉得没太大必要。本文讨论的延迟加载也主要是讨论滚动加载。
      • SeanCancer:赞一个,很全面很详细
      • Widem:没怎么看懂
      • 109cd81cc4f1:没明白padding-top如何实现宽高比,如果是背景图的话可以理解,这个没想通,求指导
        109cd81cc4f1:@齐修_qixiuss 明白了,谢谢:smile:
        齐修_qixiuss:@辉卫无敌 因为padding-top是根据宽度来计算的,所以设置padding-top之后,父容器的宽高就是根据宽高比来撑开的,接下来,设置img为绝对定位占满父容器即可。
      • 初雪落在未名的冬季:小白看不懂
        齐修_qixiuss:@初雪落在未名的冬季 新手可以只考虑固定宽高的延迟加载,引入第三方库lazysizes后几乎不需要做什么,明白延迟加载的原理就好。
      • kosilence:关注一下

      本文标题:图片延迟加载方案

      本文链接:https://www.haomeiwen.com/subject/kksdrttx.html