使用高斯模糊的效果逐步加载图片(仿 Medium)

用过 Medium 的用户不会不记得它的图片加载方式——纯色-高斯模糊-加载完成并显示。

这是一种很优雅的图片预加载的方式(因为 Medium 的图片质量都很高,如果全部一下加载的话,需要的时间难以想象,所以,这是一种很棒的做法)。从第一次打开 Medium 这个网站开始,我就被这种技术给吸引住了——好吧,直到今天才去研究它。

在 Medium 网站,打开任何一篇文章,然后,我们来 inspect 一下:


  1. <figure name="512a"  
  2.         id="512a"  
  3.         class="graf--figure graf--layoutCroppedHeightPreview graf-after--h3" 
  4.     <div class="aspectRatioPlaceholder is-locked"> 
  5.         <div class="aspectRatioPlaceholder-fill"  
  6.              style="padding-bottom: 30%;" 
  7.         ></div> 
  8.         <div class="progressiveMedia js-progressiveMedia graf-image is-canvasLoaded"  
  9.              data-image-id="1*dZnfeZiXxf2BgN3VSQuOlA.jpeg"  
  10.              data-width="3600"  
  11.              data-height="3600"  
  12.              data-scroll="native" 
  13.         > 
  14.             <img src="https://cdn-images-1.medium.com/freeze/fit/t/60/18/1*dZnfeZiXxf2BgN3VSQuOlA.jpeg?q=20"  
  15.                  crossorigin="anonymous"  
  16.                  class="progressiveMedia-thumbnail js-progressiveMedia-thumbnail" 
  17.             > 
  18.             <canvas class="progressiveMedia-canvas js-progressiveMedia-canvas"  
  19.                     width="75"  
  20.                     height="22" 
  21.             ></canvas> 
  22.             <img class="progressiveMedia-image js-progressiveMedia-image"  
  23.                  data-src="https://cdn-images-1.medium.com/fit/t/1600/480/1*dZnfeZiXxf2BgN3VSQuOlA.jpeg"  
  24.                  src="https://cdn-images-1.medium.com/fit/t/1600/480/1*dZnfeZiXxf2BgN3VSQuOlA.jpeg" 
  25.             > 
  26.             <noscript class="js-progressiveMedia-inner"> 
  27.                 &lt;img class="progressiveMedia-noscript js-progressiveMedia-inner" src="https://cdn-images-1.medium.com/fit/t/1600/480/1*dZnfeZiXxf2BgN3VSQuOlA.jpeg"&gt; 
  28.             </noscript> 
  29.         </div> 
  30.     </div> 
  31. </figure>  

可以看到,Medium 为每一张图片都设置了这么长的一段 HTML。这样做的目的就是为了让这个图片的逐步加载过程能够平滑如一,同时还能在一定程度上提升用户体验。就算图片没有加载出来,显示给用户的是一个高斯模糊的图片,其实也不失美感。

那么,这个图片的逐步加载过程具体是什么样的呢?

  1. 渲染一个 div 容器,这个容器就是用来显示最终展示给用户的图片的。通过对容器设置一个百分比的 padding-bottom 来让其比例和大小与最终图片的比例和大小相同,这样,就能避免图片加载出来的时候导致的页面的重排;
  2. 使用 img 标签来加载一张原图质量的 10% ~ 20% 左右的图片,这张图片的质量很低,而且很小,所以可以马上加载出来;
  3. 一旦小图加载完成,就开始使用 canvas 来进行绘制,添加模糊效果,同时,开始请求最终要加载的大图;
  4. 当最终的大图也加载完成之后,显示大图,隐藏掉 canvas。

以上就是 Medium 的做法。

我们可以自己来实现这个效果,实现过程如下:

  1. 渲染一个容器,保持与原图的比例和尺寸相同,填充一个较浅的背景色;
  2. 先加载小图,同时使用模糊效果;
  3. 小图加载完成,开始请求大图;
  4. 大图加载完成,显示大图,隐藏小图。

所以,综合来看,其实并不复杂。

首先,我们可以把大图和小图的 URL 和尺寸都存起来,通过标签的 data 属性去动态获取。所以,我们的 HTML 可以像下面这样写:


  1. <figure name="blur" 
  2.         class="blur-img-container" 
  3.         data-real-width="1174" 
  4.         data-real-height="670" 
  5.         data-src="images/sm2.jpeg" 
  6.         src="https://cdn-images-1.medium.com/max/2000/1*0WwtDkE1q6HGZwD6Kn9SuQ.jpeg" 
  7. ></figure>  

其中各个参数代表的含义是:

  • data-real-width: 大图的宽度
  • data-real-height: 大图的高度
  • data-src: 小图的 URL
  • src: 大图的 URL

同时,我们需要定义一些 CSS 的 class 来对大图和小图进行处理:


  1. .blur-img-container { 
  2.     position: relative; 
  3.     background: #eeeeee; 
  4.     background-size: cover; 
  5.     overflow: hidden; 
  6.  
  7. .blur-img-container img { 
  8.     position: absolute; 
  9.     top: 0; 
  10.     left: 0; 
  11.     width: 100%; 
  12.     height: 100%; 
  13.     opacity: 0; 
  14.     transition: all 0.4s ease-in-out; 
  15.  
  16. .blur-img-container .thumb-loaded { 
  17.     opacity: 1; 
  18.     filter: blur(10px); 
  19.     transform: scale(1); 
  20.  
  21. .blur-img-container .large-loaded { 
  22.     opacity: 1; 
  23.  
  24. .blur-img-container .thumb-hidden { 
  25.     opacity: 0; 
  26. }  

然后,我们的重点在于 JavaScript 的处理。

  • 需要动态的设置每个图片的容器的 padding-bottom 以防止页面发生重排;
  • 通过 image 的 onload 事件来控制其样式和进度

第一点,动态设置我们的容器的 padding-bottom。可以通过计算宽高比然后换算成百分比:


  1. elem.style.paddingBottom = `${(realHeight / realWidth) * 100}%`; 

第二点,使用图像的 onload 事件来控制加载的进度:


  1. let thumb = new Image(); 
  2. thumb.src = thumbSrc; 
  3. thumb.onload = () => { 
  4.     // 小图加载完成,显示小图,设置样式 
  5.     setStyle(thumb, 'thumb-loaded'); 
  6. }; 
  7. elem.appendChild(thumb); 
  8.  
  9. let realImg = new Image(); 
  10. realImg.src = lgSrc; 
  11. realImg.onload = () => { 
  12.     // 大图加载完成,显示大图,隐藏小图 
  13.     setStyle(realImg, 'large-loaded'); 
  14.     setStyle(thumb, 'thumb-hidden'); 
  15. }; 
  16.  
  17. // 将大图添加到页面中 
  18. elem.appendChild(realImg);  

其实,只要把上面两点主要的功能做好了,我们的这个效果基本上就实现了。

可以通过我的 GitHub Repo 来查看完整的源代码和例子 blur-image

同时,我将这个小功能封装成了一个 package,需要的朋友可以通过 npm install blur-image 或者 bower install blur-image 进行安装和使用。具体的安装和使用方法可以查看文档。

作者:Erichain_Zain

来源:51CTO

时间: 2025-01-21 01:25:29

使用高斯模糊的效果逐步加载图片(仿 Medium)的相关文章

javascript实现瀑布流动态加载图片原理_javascript技巧

本文实例为大家分享了js瀑布流加载效果,动态加载图片,供大家参考,具体内容如下 鼠标滚动事件,当鼠标滚动到下边,动态加载图片. 1. HTML代码     <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>js实现瀑布流效果-动态加载图片</title> <link rel="stylesheet" href="

jquery 预加载图片效果插件与实例

文章一款告诉你如何利用jquery 预加载图片的实例教程,同时你也可以根据它出制作出漂亮的jquery 预加载图片效果哦. <!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/x

Android 异步加载图片,使用LruCache和SD卡或手机缓存,效果非常的流畅

异步加载图片的例子,网上也比较多,大部分用了HashMap<String, SoftReference<Drawable>> imageCache ,但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠.另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应

jQuery滚动加载图片效果的实现_jquery

复制代码 代码如下: <BR>/****************滚动加载图片函数****************/     function scrollLoading(){          var st = $(window).scrollTop(), sth = st + $(window).height();          var $targetpics = $("img.scrloadpic");          var len = $targetpics.

jQuery oLoader实现的加载图片和页面效果_jquery

oLoader使用方法 不管是oLoader还是oPageLoader都是基于jQuery,所以调用前请先加载jquery库,作者已经将两个插件集成到一起:jquery.oLoader.min.js,已经打包好请戳源码下载. 调用jQuery oLoader非常简单,一句话如下: 复制代码 代码如下: $('#element').oLoader(); 使用oLoader加载图片: 复制代码 代码如下: $(function(){   $('img').oLoader({     waitLoad

jQuery/JavaScript 实现的异步加载图片效果

在上代码之前先说一下简单的原理,我们知道在 img 标签中的 src 属性是指向图片地址,要实现异步加载,就先暂时不给 src 属性赋值,而是先找个中间变量的属性 data-src,把图片地址写在 data-src 属性里,然后当触发 onclick 事件的时候,把 data-src 的值复制给 src,也就实现了异步加载. 代码时间到,因为无论是 jQuery 还是 JavaScript 的方法,HTML 的结构是相同的,如下:  代码如下 复制代码 <div id="box"

Android ViewPager加载图片效果

目前项目中需要用到ViewPager加载图片,现在在此记录一下. 首先先看布局文件:activity_main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.c

Flash相册加载图片完毕等比缩放的类

每次做相册类的flash的时候,图片加载完毕之后都要写等比缩放的函数来处理加载图片. 今天又遇到了,也不知道哪根筋不对了,弄了十几分钟老是算法有错误.好好的一个美女图片被搞的惨不忍睹.所以写了这个类 直接放到我的as包里,以后不要再这么麻烦了. 贴一下,能用的朋友就用一用.看不上眼的也不要拍砖啊. 下边是代码及注释说明: /*   等比缩放   as1984 - qq:38657783   20091221   请注意包路径,我的as包都放在tools目录下.所以包的路径是 tools   如果

Android之ListView异步加载图片且仅显示可见子项中的图片

折腾了好多天,遇到 N 多让人崩溃无语的问题,不过今天终于有些收获了,这是实验的第一版,有些混乱,下一步进行改造细分,先把代码记录在这儿吧. 网上查了很多资料,发现都千篇一律,抄来抄去,很多细节和完整实例都没看到,只有自己一点点研究了,总体感觉 android 下面要显示个图片真不容易啊. 项目主要实现的功能: 异步加载图片 图片内存缓存.异步磁盘文件缓存 解决使用 viewHolder 后出现的图片错位问题 优化列表滚动性能,仅显示可见子项中的图片 无需固定图片显示高度,对高度进行缓存使列表滚