当前位置: 首页 > 科技观察

图片懒加载从简单到复杂

时间:2023-03-14 14:34:50 科技观察

图片懒加载是前端性能优化的一个非常重要的手段。本文将从最简单的懒加载场景开始,逐步增加复杂度。希望对图片常见的懒加载场景以及该场景下对应的解决方案进行说明,希望对大家有所帮助。为什么图片延迟加载假设用户访问一个页面时,加载了该页面的所有图片(即使这些图片不在用户当前窗口中),在弱网环境或网速较慢的环境下,下载这些“冗余”的图片会占用用户本来就非常有限的带宽,伤害用户体验(比如影响其他资源的下载)。所以对于网站的图片,理想的方式就是懒加载(按需加载)。图片懒加载的原理对于浏览器内部的各种资源都有自己的一套优先级定义,浏览器会优先加载优先级高的资源。如果我们不对图片进行延迟加载,默认情况下,资源的优先级如下。这些高优先级的图片会占用其他资源的下载带宽,可能会导致一些关键资源(比如xhr调用)加载缓慢,页面速度变慢。图片懒加载的简单实现图片懒加载的思路一般是在页面加载的时候加载一个小尺寸的占位图片(小于1kb),然后通过js选择性的加载真实图片。最简单的实现之一如下://index.cssimg[src]{filter:blur(0.2em);}img{filter:blur(0em);transition:filter0.5s;}(functionlazyLoad(){constimageToLazy=document.querySelectorAll('img[src]');constloadImage=function(image){image.setAttribute('src',image.getAttribute('src'));image.addEventListener('load',function(){image.removeAttribute("src");})}imageToLazy.forEach(function(image){loadImage(image);})})()延迟加载后,资源优先级如下。图片懒加载进阶实现——滚动加载上面的方案并不完美。对于用户来说,不在窗口中的图片可能根本就不是用户关心的图片,所以我们可以让这些图片在加载前出现在用户窗口中。使用IntersectionObserver,我们可以在图片滚动到窗口时加载图片。(functionlazyLoad(){constimageToLazy=document.querySelectorAll('img[src]');constloadImage=function(image){image.setAttribute('src',image.getAttribute('src'));image.addEventListener('load',function(){image.removeAttribute("src");})}constintersectionObserver=newIntersectionObserver(function(items,observer){items.forEach(function(item){if(item.isIntersecting){loadImage(item.target);observer.unobserve(item.target);}});});imageToLazy.forEach(function(image){intersectionObserver.observe(image);})})()上面的demo都在https:///github.com/hateonion/lazy-load在此repo中。如何选择合适的占位图片在上面的演示中,我们使用了占位图片。其实图片的位置是否确定对我们选择占位图片有很大的影响。图片尺寸已知图片尺寸已知的场景一般是博文的标题图片或者网站上的一些固定尺寸的缩略图。这些图片的大小一般是固定的,一般不会改变。对于这种场景,我们可以加载一张相应尺寸的占位图片(如上一节的demo)。我们可以自己裁剪相应大小的placeholder图片或者使用http://placeholder.com/这样的服务获取placeholder图片。未知图片尺寸当图片尺寸未知时,我们一般需要生成相应的缩略图,然后加载我们生成的缩略图来做占位符。为了生成这些缩略图,可以调用imagemagick或者调用一些在线的图片分割服务(比如七牛)。延迟加载可防止布局抖动。图片延迟加载时,由于图片大小可变,浏览器很难计算出需要为图片预留的位置。.所以在加载图片的时候,网页的布局会抖动。(图片来自Fromhttp://davidecalignano.it/lazy-loading-with-responsive-images-and-unknown-height/)即使我们选择一个小的占位符,也可以在毫秒内完成下载,而??用户可能不会注意布局抖动。但是在一些性能比较差的设备上,这种布局的抖动还是会在一定程度上影响用户体验。为了完全避免布局闪烁,我们可以使用宽高比框技术来制作占位符元素。

.lazy-load__container{position:relative;display:block;height:0;}.lazy-load__container.feature{//featureimage的纵横比设置为42.8%//post图片等其他图片,纵横比可能不同,可以使用其他cssclasses设置padding-bottom:42.8%;}。lazy-load__containerimg{position:absolute;top:0;left:0;height:100%;width:100%;}结果上面实现的原理其实很简单,因为padding-bottom(或者padding-top)被声明为百分比基于元素生成的框的宽度来计算百分比,所以我们使用padding-bottom来声明一个对应纵横比的容器。这个容器的具体尺寸将由其尺寸确定的外部元素决定,但纵横比将始终保持不变。并且图片的大小设置为容器大小的100%,保证图片始终和容器的大小一致。需要注意的是,上述方法无法适应图片比例不一致的网站(比如本站),但好在现在大多数网站为了用户体验,对图片比例都有明确的要求。大多数情况下,我们只会适配以保证网站上常用的几张图片的宽高比例。像Medium这样懒加载图片在Medium上懒加载图片的体验,相信看过Medium文章的同学都有体会,可以说是非常流畅。它背后的技术其实是我们上面提到的几种技术的结合。使用纵横比框来创建占位符元素。解析html时,只加载了一张小图,并添加了模糊效果。最后用js选择性加载真实图片。Demo如下CodePenbyJoséM.Pérez总结在用户当前窗口延迟加载图片可以提高页面加载性能。懒加载的思路是在解析HTML的时候先加载一个占位图片,最后用js选择性加载真实图片。如果需要滚动,可以使用IntersectionObserver。对于固定大小和可变大小的图像,我们可以选择不同的服务或占位符图像。我们可以使用aspectratiobox来解决图片尺寸不确定导致的布局抖动问题。