你在Facebook和Medium上遇到过渐进式图像,当页面滚动到视图中时,模糊的低分辨率图像被清晰的全分辨率图像所取代。预览图片非常小(可能是20px宽的高压缩JPEG),文件可以小于300字节,并且马上有一个快速加载的模糊轮廓,需要的时候通过延迟加载来加载实际图像。渐进式图像很棒,但当前的解决方案很复杂。幸运的是,我们可以使用HTML5/CSS3/JavaScript构建示例,示例代码:快速且轻量级-只有463字节的CSS和1007字节的JavaScript(压缩)支持响应式图像加载更大或更高分辨率(视网膜)屏幕的替代版本否依赖项-适用于任何框架与所有现代浏览器(IE10+)兼容在旧浏览器中逐步增强,或者当JavaScript/图像无法加载时易于使用我们的演示和GitHub代码这是我们的演示示例从GitHubHTML代码下载代码我们将实施带有一些基本HTML的渐进式图像:这里:full.jpg是一张清晰的大图,地址在hreftiny.jpg是我们已有的轻量级预览图一个小的工作系统,没有任何javascript(可能在旧浏览器中会失败),用户可以预览完整的图片通过点击。两张图片的宽高比必须一样,比如full.jpg是800*200,它最终的宽高比是4:1,那么tiny.jpg可以是4:1,但是不能用30px的宽度,因为这样的话高度将是一个分数而不是7.5px。请注意链接和预览图像上使用的类,我们将在JavaScript中使用这些类。InlineorOutlineImagePreview图片可以数据URL的形式内联,例如:Inlineimage会立即显示,需要更少的HTTP请求,并避免额外的页面回流,但是:添加或更改内联图像需要更多资源(尽管可以借助Gulp等帮助构建)base-64编码效率较低低,通常为30%大于二进制数据(虽然这被额外的HTTP请求标头抵消了)内联图像无法在本地缓存,它们只能缓存在HTML页面中,并且如果不发出相同的请求,则无法在另一个页面中缓存该页面使用HTTP/2以减少对内联图像的需求。更实用:如果内联图片只是在单个页面上使用,并且需要的代码量较小(比如URL比较短),内联图片是一个不错的选择。CSS让我们先定义容器样式:a.progressive{position:relative;显示:块;溢出:隐藏;outline:none;}这个是设置container容器的布局属性。如有必要,链接可以应用其他类和样式设置大小或位置。您可以考虑使用精确尺寸或使用padding-top来强制执行固有的纵横比,这可确保在调整容器大小之前避免图像加载和回流,但这需要计算每个图像的大小和宽度进行比较。我选择更简单的方法:预览和大图像必须具有相同的纵横比(见上文)预览图像几乎会立即定义容器的高度,因为它是内联的,或者再次快速加载提示:如果你在有很多图片的页面,最好定义一个固定宽度和高度的容器,比如图库(所有图片可能具有相同的纵横比)。当加载完整的大图像并且点击事件停止时,容器上的“replace”类将被删除,因此我们可以删除标准链接指针。a.progressive:not(.replace){cursor:default;}容器中的预览图和大图根据容器的宽度调整大小:a.progressiveimg{display:block;宽度:100%;最大宽度:无;高度:自动;border:0none;}注意height:auto是必须的,IE10/11在计算图片高度时可能会出错。预览图像以2vw的长度进行模糊处理,确保模糊处理后无论页面大小如何都具有相似的轮廓。将overflow:hidden应用于容器可为容器提供硬边。它还按1.05倍缩放,防止通过图片模糊的外边缘看到图片的背景颜色。这意味着我们可以显示具有令人愉悦的缩放效果的完整图像。a.progressiveimg.preview{滤镜:模糊(2vw);transform:scale(1.05);}最后我们定义图片完全显示时的样式和动画:a.progressiveimg.reveal{position:absolute;左:0;顶部:0;will-change:变换,不透明;animation:reveal1sease-out;}@keyframesreveal{0%{transform:scale(1.05);不透明度:0;}100%{变换:比例(1);opacity:1;}}大图在预览图上方,1秒内,不透明度从0增加到1,比例从1.05变为1。您可以根据需要添加其他过渡/滤镜效果。JavaScript我们遵循渐进式增强模型,因此JavaScript代码将首先检查所需的浏览器API是否可用,然后再向页面添加加载事件侦听器。//progressive-image.jsif(window.addEventListener&&window.requestAnimationFrame&&document.getElementsByClassName)window.addEventListener('load',function(){加载事件将在页面和所有资源加载时触发。我们不想要在字体、CSS、JavaScript和预览图像等基本资源完成加载之前加载大图像(这可能发生:我们使用DOMContentLoaded事件——当DOM准备就绪时触发的事件)。接下来,我们得到类nameprogressive并替换所有图像容器元素:varpItem=document.getElementsByClassName('progressivereplace'),timer;getElementsByClassName()返回一个活动的类数组HTMLCollection,匹配的元素将被添加到页面或从页面中移除。它的好处是它会接下来,我们将定义一个inView()函数,通过将其getBoundingClientRect()方法与window.pageYOffset垂直滚动位置进行比较来确定容器是否在视图中。//视图中的图像?functioninView(){varwT=window.pageYOffset,wB=wT+window.innerHeight,cRect,pT,pB,p=0;while(ppT){loadFullImage(pItem[p]);pItem[p].classList.remove('替换');}否则p++;}}当容器在视图中时,它的节点被传递到loadFullImage()函数,并且替换类被移除(该节点立即从pItemHTMLCollection中移除,因此容器不会被再次重新处理)。loadFullImage()函数创建一个新的HTMLImage()对象并根据需要设置其值,即将容器的href的值复制到src属性中并应用显示类。//替换为完整图像functionloadFullImage(item){if(!item||!item.href)return;//加载图像varimg=newImage();如果(item.dataset){img.srcset=item.dataset.srcset||'';img.sizes=项目.dataset.sizes||'';}img.src=item.href;img.className='显示';如果(img.complete)addImg();否则img.onload=addImg;加载图像后调用内部addImg函数://替换图像functionaddImg(){//禁用点击item.addEventListener('click',function(e){e.preventDefault();},false);//添加完整图像item.appendChild(img).addEventListener('animationend',function(e){//删除预览图像varpImg=item.querySelector&&item.querySelector('img.preview');if(pImg){e.target.alt=pImg.alt||'';item.removeChild(pImg);e.target.classList.remove('reveal');}});注意:禁用容器上的点击事件将图像附加到启动淡入淡出/缩放动画的页面使用animationend侦听器等待动画结束,然后复制alt内容。删除预览图像节点并从完整图像中删除显示类。此步骤有助于提高性能并防止在调整Edge浏览器大小时出现一些奇怪的裁剪问题。最后,我们必须调用inView()函数来检查所有渐进式图像容器在首次运行时是否在页面上可见。在视图中();我们还必须在页面滚动或者浏览器调整大小时调用该函数,一些老浏览器(主要是IE)可以非常快速地响应这些事件,所以我们需要限制回调以确保它不能在300毫秒内再次调用.window.addEventListener('scroll',scroller,false);window.addEventListener('resize',scroller,false);functionscroller(e){timer=timer||setTimeout(function(){timer=null;requestAnimationFrame(inView);},300);}注意下次调用requestAnimationFrame会重绘inView函数。响应式图片HTML中图片的srcset和sizes属性定义了多张不同尺寸和分辨率的图片,浏览器可以选择最适合设备的版本。上面的代码支持这个功能——给链接容器添加data-srcset和data-sizes属性,例如:加载完成后,完整的图片代码为:现代浏览器将在视图窗口宽度为800px或更高时加载large.jpg,旧版浏览器具有小视口的浏览器将加载small.jpg。具体可以参考HowtoBuildResponsiveImageswithsrcsetUsageNotes我会保持代码轻量级,随时可用,易于改进。有待优化的地方:水平滚动检查。目前仅检查垂直方向的滚动会动态添加渐进式图像。使用JavaScript动态添加的渐进式图像仅在滚动或调整大小事件发生时被替换Firefox性能。浏览器可能无法替换大图像(您可能会看到明显的闪烁)作者:CraigBuckler原文:如何构建您自己的渐进式图像加载器