图片渐进式加载方案探索

  • Google Image Search采用从图片中取出现频率高的像素作为纯色占位
  • 知乎问题详情中的图片内容模糊小图占位
  • facebook采用灰度原型图占位

目的都是为了让用户从感觉上无缝显示,给用户一种已经加载的错觉。本篇将讨论实现图片模糊渐进式加载的技术。

最近,我在浏览一篇推文的时候,发现了一种非常漂亮的图片加载效果,起初,先加载一张小小的模糊图片,随后这张图片过渡为一张完整清晰的大图。我发现,这种效果很精致,所以写下这篇文章探讨他是如何实现的。

渐进式加载

为了能够了解渐进式图片的技术原理,最好看一段DEMO。

你可以对比这个WEB页面,比较下普通图片加载与渐进式图片加载的差异:

普通加载模式: WebPageTest test

渐进图片加载模式: this page on Medium

如果你想要亲自查看这两种加载方式的差异,你可以将这两个页面在浏览器中打开,在开发者控制面板中关闭缓存并且降低http响应速度(控制面板中可调节网速与网络类型),你会发现该页面将需要更多的时间获取图片,当获取到图片文件后你可以看到这种渐进式效果。

下面是这项技术的要点:

  • 渲染一个div标签,用于容纳要呈现的图片,在该容器中再加入一个div标签并设置他的padding-bottom属性为百分比,该div用于将父容器div撑起来以便于放置后续加入父容器的绝对定位的图片。也就是说,这一div子元素就是图片的可是区域,超出这个范围的图像将被隐藏(当然最好overflow设置为隐藏)。这样做的目的也是为了在加载完大图并插入页面中后,避免用户代理重新绘制渲染,提升性能。详细介绍可以看这篇文章:intrinsic placeholders
  • 加载小版本的图片。这时,已经加载出一个缩小版的JPEG图片,这张图片的图片质量很低(大约20%,最高质量为100%,可在ps或后台模块中配置这些参数)。这种缩小版的图片标签一般跟随html文件一同传输,所以在用户代理解析html到该img标签时便会请求获取该小图。
  • 一旦缩小版的图片请求完毕,它将被绘制到canvas画布中,通过调用自定义的blur()函数来绘制。
  • 绘制完毕后,继续等待大图的加载。直到大图加载完毕后,先前用于渲染小图的canvas画布将隐藏。

上面所有的过渡都非常平滑,这要归功于CSS3动画的实现。

代码片段

<figure>
  <div>
    <div/> <!-- this div keeps the aspect ratio so the placeholder doesn't collapse -->
    <img/> <!-- this is a tiny image with a resolution of e.g. ~27x17 and low quality -->
    <canvas/> <!-- takes the above image and applies a blur filter -->
    <img/> <!-- the large image to be displayed -->
    <noscript/> <!-- fallback for no JS -->
  </div>
</figure>

具体案例中的代码,你可以看下这些标签具体如何使用。

<figure name="7012" id="7012" class="graf--figure graf--layoutFillWidth graf-after--h4">
  <div class="aspectRatioPlaceholder is-locked">
    <div class="aspect-ratio-fill" style="padding-bottom: 66.7%;"></div>
    <div class="progressiveMedia js-progressiveMedia graf-image is-canvasLoaded is-imageLoaded" data-image-id="1*sg-uLNm73whmdOgKlrQdZA.jpeg" data-width="2000" data-height="1333" data-scroll="native">
      <img src="https://cdn-images-1.medium.com/freeze/max/27/1*sg-uLNm73whmdOgKlrQdZA.jpeg?q=20" crossorigin="anonymous" class="progressiveMedia-thumbnail js-progressiveMedia-thumbnail">
        <canvas class="progressiveMedia-canvas js-progressiveMedia-canvas" width="75" height="47"></canvas>
        <img class="progressiveMedia-image js-progressiveMedia-image __web-inspector-hide-shortcut__" src="https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg" src="https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg">
        <noscript class="js-progressiveMedia-inner">&lt;img class="progressiveMedia-noscript js-progressiveMedia-inner" src="https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg"&gt;</noscript>
    </div>
  </div>
</figure>

使用CSS的滤镜函数同样能实现上面的效果。

你同样可以通过关闭缓存降低网速来清楚的看到这一过程。

显然,想要使用这一方法完整的渲染一张大图片需要书写很多代码(html结构,css过渡样式以及js的监听事件与渲染画布等),甚至在你的网站上加入这项提升用户体验的功能会让你感到沮丧。

几年前,要想完成动画效果或者模糊滤镜效果是几乎不可能的,摆在开发者面前的很现实的问题是宝贵的加载时间的瓶颈(即网速),而不是用户设备的性能,我们可以完成这种可视化的探索。

完全掌控图片加载技术,你需要知道这些:

  • Lazy Loading—懒加载技术,使用JS控制图片何时请求。全部图片使用相同的缩略图,当图片进入视图后才完整的请求大图,大大节省宽带,提升前后端性能。
  • Better placeholder—占位符,缩略图占用空间非常小,大约仅占2KB左右,使用一张模糊的图片作为占位符,总好过于使用纯色背景。
  • Tailores image sizes—定制图片大小,使用不同的渐进式图片大小取决于请求图片de设备参数。

多变体

在找到适合你的技术之前,我想使用一个相似的技术——我的站点使用的技术。

内联图像数据

取代使用请求缩略图的形式的另一种形式就是内联图像数据。使用URL数据的形式存储图片在技术上是可行的。不需要额外的请求,可完全内嵌于html文章中一并被用户代理接收

原文链接:How Medium does progressive image loading

上一篇《浅学先秦《周易》之《乾》卦》

下一篇《Facebook占位加载动效知乎的前端实现原理》

永久链接 http://www.shuaihua.cc/article/explore-gradual-model-loading-display-way

快速跳转 心头好文 - ux - 《图片渐进式加载方案探索》

发布日期 2017-12-12 14:13:47 周二

版权声明 自由转载-非商用-非衍生-保持署名(创意共享3.0许可证