美文网首页前端小问题
优化大量图片的加载

优化大量图片的加载

作者: wsgdiv | 来源:发表于2021-01-12 17:37 被阅读0次

    含摘录,非原创
    图片懒加载,在页面上的未可视区域可以添加一个滚动条事件,判断图片位置与浏览器顶端的距离与页面的距离,如果前者小于后者,优先加载。图片懒加载的思路一般时当页面加载时加载一个尺寸很小的占位图片(1kb以下),然后再通过js选择性的去加载真正的图片。
    一个最简单的的实现如下:

    <!-- index.html -->  <img src="placeholder.jpg" src="real_image.jpt" />
    // index.css
    
      img[src] {
          filter: blur(0.2em);
      }
    
      img {
          filter: blur(0em);
          transition: filter 0.5s;
      }
    //js
    (function lazyLoad(){
        const imageToLazy = document.querySelectorAll('img[src]');
        const loadImage = function (image) {
            image.setAttribute('src', image.getAttribute('src'));
            image.addEventListener('load', function() {
                image.removeAttribute("src");
            })
        }
    
        imageToLazy.forEach(function(image){
            loadImage(image);
        })
    })()
    

    运用Intersection Observer 我们可以做到当图片滚动到视窗后再加载该图片。

    (function lazyLoad(){
        const imageToLazy = document.querySelectorAll('img[src]');
        const loadImage = function (image) {
            image.setAttribute('src', image.getAttribute('src'));
            image.addEventListener('load', function() {
                image.removeAttribute("src");
            })
        }
    
    
        const intersectionObserver = new IntersectionObserver(function(items, observer) {
            items.forEach(function(item) {
                if(item.isIntersecting) {
                    loadImage(item.target);
                    observer.unobserve(item.target);
                }
            });
        });
    
        imageToLazy.forEach(function(image){
            intersectionObserver.observe(image);
        })
    })()
    

    为了完全避免布局闪动,我们可以采用aspect ratio boxes 的技术来制作一个占位用的元素。

    <div class="lazy-load__container feature">
      <img src="placeholder.jpg" src="real.jpg" />
    </div>
    
    .lazy-load__container{
        position: relative;
        display: block;
        height: 0;
    }
    
    .lazy-load__container.feature {
        // feature image 的高宽比设置成42.8%
        // 对于其他图片 比如 post图片,高宽比可能会不同,可以使用其他css class去设置
        padding-bottom: 42.8%;
    }
    
    .lazy-load__container img {
        position: absolute;
        top:0;
        left:0;
        height: 100%;
        width: 100%;
    }
    

    上面这个实现的原理其实很简单,由于 padding-bottom (或者 padding-top)声明为百分比时是根据元素生成的box的 width 去计算百分比的,所以我们通过padding-bottom去声明一个对应高宽比的container。而这个container的具体尺寸会由尺寸确定的外层元素确定,但是高宽比始终保持一致。
    而图片的尺寸设置成100%container的尺寸保证图片始终和container的尺寸保持一致。
    需要注意的是上面这个方法并不能适配图片比例不一致的网站(比如本站),不过好在,为了用户体验,现在绝大多数网站的图片比例都有明确的要求,绝大多数情况下我们只适配保证网站常用的的几种图片宽高比例即可。
    以京东sale活动页为例,我们随便选取一个活动地址,查看网页源代码,我们可以找到形如这种结构的img标签:

    <img class="J_imgLazyload" src="//img14.360buyimg.com/cms/g10/M00/13/04/rBEQWFFj4PUIAAAAAAAESxyqJLUAADvdAIHC9oAAARj186.gif" original="//img11.360buyimg.com/cms/jfs/t12118/41/1394617476/43413/2253395a/5a1f7569N63f38100.jpg" />
    

    我们试着来分析一下这个img标签的结构,首先我们在浏览器中直接打开该img标签的src,结果发现这张图是一张10*10的空白图片。我们发现img标签中还有一个伪属性original,里面也有一个很像是图片的链接。
    结果,original中存放的才是真实图片的路径。当页面滚动时,遍历当前页面需要进行懒加载的图片,判断图片是否在可视区域内,如果在的话,则取存放在伪属性中的真实src替换当前的src。
    (1)滚动函数的节流
    每次滚动事件都将执行:选择页面所有图片→遍历→筛选在当前视窗内的图片→使用真实src替换占位图。以上过程是一个非常耗时的过程,尤其是在筛选符合条件的图片的步骤。因此,我们需要对滚动事件进行节流:只有当后一次触发滚动与前一次触发滚动的时间间隔大于一定阈值时,才认为这次滚动生效。
    (2)预加载
    将提前加载前后各1屏幕内的图像,如此一来,当用户在当前视窗内继续上滑或下滑时,该屏内的图片已经提前加载完毕,用户就不会感知到图片从白屏到显像的这种抖动过程,大大提升了用户体验。
    4、更优的用户体验
    在国内网站中,知乎官网在图片懒加载部分做得较为领先,拥有很好的用户体验。让我们先来看一下效果,随便打开一个知乎问答页(在PC环境中打开):知乎问答页示例

    效果图:

    图片

    仔细观察,我们可以看到这样一种效果:图片在由白至清晰的过程中有一种模糊渐变的效果,相比于直接替换空白占位图的方案,这种方式不会给用户带来突兀感。

    查看页面源代码,我们发现直出的页面中img标签是以这种形式存在的:

    图片

    img标签及其内的信息作为字符串保存在noscript标签中,src中为一张低品质图片,data-original中为真实图片地址,同时有一个占位的span元素。当页面滚动到该noscript标签对应的位置时,解析出noscript标签中的img,并替换占位span元素:

    图片

    此时将先加载低质量的小图,再加载清晰的高质量原图:

    图片

    如此一来,用户将在极短的时间内就能看到图片的大致轮廓。随后等真实图片加载完毕后,再使用CSS控制图片逐渐变清晰,整个过程顺畅自然,一气呵成。在网速较差的环境下,这种方式也能有很优雅的降级体验。
    5、更加富有脑洞的图片懒加载策略:
    这里有一篇国外论坛的文章:How to use SVG as a Placeholder, and Other Image Loading Techniques,主题是利用SVG生成各种风格的占位图。国内也有人对其进行了简要翻译:图片加载时使用 SVG 作为图片 placehold。

    我们在上文中提到的占位图都是一个空白图片的形式,而这篇文章中提出了一些非常新颖而前卫的占位图生成方式:

    (1)梯度底色占位图:
    图片

    这种方式是通过后端的处理,将img标签中的图片提前做一次解析,处理为一种带梯度的SVG元素,这种SVG元素所占体积极小,可以随页面一起直出。

    换种思路,如果我们不想使用SVG,也可以直接将图片的主要背景颜色提取出来,使用base64方式直出该图片。

    (2)SVG色块:
    图片

    我们可以通过一些简单的SVG元素拼接,描绘出图片的基本轮廓,并在此基础上加上一个模糊滤镜,也可以达到很好的占位图效果。

    (3)二值化剪影:
    图片

    效果图如上。

    如果图片为css图片,可以使用CSSsprite,SVGsprite,Iconfont、Base64等技术。
    CSS Sprite,中文翻译为雪碧图,Ta主要解决的是小图片过多以及耗费网络资源的问题,核心原理就是将图片合并成一张大图下发到客户程序,并利用属性来对其进行定位和切割的技术。
    Css Sprite使用方法:

    1、将用到的背景图片压缩为zip格式的压缩包
    2、用Css图片拼合生成器将其拼合成一张图片,然后下载该图片
    3、拼合完成后会生成相应的Css规则,该文件定位了每个图片的位置及图片的宽度和高度
    4、在Css样式中定位背景图片,例如:
    相关文章:scrollTop,offsetTop,scrollLeft,offsetLeft

    相关文章

      网友评论

        本文标题:优化大量图片的加载

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