【译】运用Mobify.js让你的图片自动相应化

在Web开辟社区,响应式图片已成为最大的挫败之一。缘由也很简朴:页面均匀大小产物能从客岁的1MB抵达了惊人的1.5MB。个中图片大小的增进比例就占了页面大小增进的60%或更多,而且这个比例还在不停爬升。

绝大多数的页面是可以下降页面大小的,假如你借助基于装备宽度、像素密度和当代图象花样(比方WebP)等优化前提的话。这些减重的要领可以加速载入时刻,让用户介入更多、停止更长时刻。不过这里不是争辩是不是应当为差别的装备优化图象,而是关于应当怎样去做。

抱负状况下,我们应当继承运用img标签,然后浏览器会下载适配装备宽度、适配页面规划的图片。然则,如许的功用实在并不存在。完成靠近这类功用的要领之一是在javascript实行历程当中改变img元素的src属性,但超前的预剖析器(或预加载)扼杀了它的能够性。

战胜这个题目标第一步是建立一个基于标记的处置惩罚计划,该计划许可基于装备的功用来替换图象的泉源。跟着W3C响应式图片交换社区制造的picture元素(只管如今还没有浏览器完成了它)的引入,这个题目已被处置惩罚了。

不过,picture元素的引入也带来了新题目:
开辟人员如今必需在每一个断点为每一个图片天生一个自力的asset。而开辟者真正须要的是一个可以将一张高分辨率图片自动转化为适配装备的小图片的计划。抱负状况下,这个自动化处置惩罚计划可以让每张图片只要求一次,而且充足语义化和向后兼容。 Mobify.js的图象API供应了该计划。

<picture> 元素成为将来的最好实践

picture元素是当前替换img元素的先行者,因为它使得开辟者可以为差别的屏幕分辨率指定差别的图片,处置惩罚了机能和art direction(只管新提出的srcN发起值得斟酌)题目。典范的设置包括定义断点,为差别断点天生图象,然后为图象写入picture标记。我们看看怎样通使下面的图片变得响应性:

《【译】运用Mobify.js让你的图片自动相应化》

我们运用了320、512、1024和2048像素基线。

起首,我们须要为每张图片天生差别的分辨率的副本,可以经由历程命令行东西,比方 Image Optim或运用Photoshop的“存储为web所用花样”功用。接下来,我们运用下面的标记:

    <picture>
        <source src="responsive-obama-320.png">
        <source src="responsive-obama-512.png" media="(min-width: 512px)">
        <source src="responsive-obama-1024.png" media="(min-width: 1024px)">
        <source src="responsive-obama-2048.png" media="(min-width: 2048px)">
        <noscript><img src="responsive-obama-320.png"></noscript>
    </picture>

上面的代码有个题目,在它的设置中,我们的图片能够不会对挪动装备优化。下面是一张缩放到320像素宽的图片:

《【译】运用Mobify.js让你的图片自动相应化》

图片中的人物已很难辨别。为了更好的顺应小屏幕,我们须要借助art direction的气力,
为小屏幕裁切这张图片。

《【译】运用Mobify.js让你的图片自动相应化》

因为这个文件不是原始图片的简朴缩放版本,须要给它一个特别的定名构造(所以,用responsive-obama-mobile.png替换了responsive-obama-320.png

    <picture>
    <source src="responsive-obama-mobile.png">
    <source src="responsive-obama-512.png" media="(min-width: 512px)">
    <source src="responsive-obama-1024.png" media="(min-width: 1024px)">
    <source src="responsive-obama-2048.png" media="(min-width: 2048px)">
    <noscript><img src="responsive-obama-512.png"></noscript>
</picture>

然则假如我们要支撑高DPI(点每英寸)装备呢?
picture 元素的范例中有一个srcset属性,该属机能让我们很轻易为差别分辨率指定差别的图片。以下是我们运用picture元素后的代码:

<picture>
<source srcset="responsive-obama-mobile.png 1x, responsive-obama-mobile-2x.png 2x">
<source srcset="responsive-obama-512.png 1x, responsive-obama-1024.png 2x" media="(min-width: 512px)">
<source srcset="responsive-obama-1024.png 1x, responsive-obama-1024.png 2x" media="(min-width: 1024px)">
<source srcset="responsive-obama-2048.png 1x, responsive-obama-4096.png 2x" media="(min-width: 2048px)">
<noscript><img src="responsive-obama-512.png"></noscript>

这里引入了一对新文件(esponsive-obama-mobile-2x.pngresponsive-obama-4096.png),它们也必需天生。到如今为止,我们具有同一个图片的6个差别版本的副本。

让我们更进一步。假如我们想运用当代化的花样,比方WebP来读取我们的图象,须要经由历程推断浏览器是不是支撑吗?倏忽,我们须要天生的文件数目从6个增加到12个。老实说,没人情愿因为差别的分辨率而给每一个图片天生多个版本的图片副本,而且须要在代码标记上更新这些图象版本。
我们须要让它自动化!

抱负的响应式图片事变流程

抱负的事变流程是如许的,它许可开辟者上传分辨率尽量高的图片同时依旧运用img元夙来抵达自动为差别的浏览器重置图片大小和紧缩图片的目标。img元素很庞大,这个简朴的标签处置惩罚了简朴的题目:为互联网的用户展现图片。抱负状况下,我们能经由历程一种高效的要领继承相沿这个元素而且向后兼容。然后,当art direction arises 和权衡图片下限的需求不能满足时,我们可以运用picture元素,它语法中内建的分支逻辑很圆满。

这个抱负的事变流可以经由历程Mobify.js的响应式图象API来完成。Mobify.js是一款改良响应式网站的开源库,供应了响应式图片、javascript和css的优化,自顺应模板等等。它的图象API可以自动重置大小和紧缩imgpicture元素,必要状况下,在后端以至不须要改变任何一行标记代码。简朴的上传高分辨率材料然后让API去体贴接下来的事变。

不修改后端代码自动让图片响应化

响应式图片之所以成为一个难以处置惩罚的题目是因为超前的预剖析器,它阻挠我们经由历程javascript改变img元素的src属性。预剖析器是浏览器的一个功用,经由历程天生一个自力的线程(自力于衬着线程以外),定位资本并使其并行下载,从而让资本尽快的最先下载。预剖析器的事变在响应式设想涌现之前很有意义,但在如今的多装备的状况下,代码标记的图象不一定是我们愿望用户看到的;因而,我们须要思索一种许可开辟者掌握资本加载的同时不捐躯预加载的优点的API。在这个题目上,假如想要相识更多细节,可以斟酌看看teve Souders的“I <3 Image Bytes.”

很多开辟者为了防止预加载采纳的一种要领是经由历程img的data-src属性手动改变src属性,奇妙地让预加载器疏忽了这些图象,然后运用javascript将src属性的值用data-src的替换。

经由历程Mobify.js 的 捕获 API,我们防止了上面的要领,让我们在保证机能的状况下又不失语义(无需 <noscript>data-src )。捕获手艺阻挠了初始页面资本的预加载,但这并不障碍并行下载。运用Mobify.js的图象API和捕获手艺相结合,我们能经由历程一个javascript标签完成图象的自动响应化。

下面是挪用API的的代码:

Mobify.Capture.init(function(capture){
    var capturedDoc = capture.capturedDoc;
    var images = capturedDoc.querySelectorAll('img, picture');
    Mobify.ResizeImages.resize(images, capturedDoc) 
    capture.renderCapturedDoc();
});

它获取了页面的一切图片,然后重写的src的值以下:

http://ir0.mobify.com/<format><quality>/<maximum width>/<maximum height>/<url>

比方,假如该API在安卓最新版的chrome下运转,装备的css像素为320,像素比例为2,那末图片就会从

<img src='cdn.mobify.com/mobifyjs/examples/assets/images/forest.jpg'>

变成

<img src='//ir0.mobify.com/webp/640/http://cdn.mobify.com/mobifyjs/examples/assets/images/forest.jpg'>

forest图片会被调解到640px宽,而且,因为chrome支撑WebP,我们可以因而受益,将来可以下降图片的体积。在第一次要求以后,图片就会被Mobify的CDN缓存,以备下次运用。因为这个图片不须要任何art direction,我们可以继承运用img元素。

你可以看看这个自动调解图片大小的例子。翻开网站调试东西,肯定原始图片没有被下载!

运用这个计划,我们简化了事变流程。我们仅仅上传了一个高分辨率的图片,然后让API完成图片的自动化调解大小。中心不须要代办历程,没有改变任何属性-只是一断javascript。去吧,试着复制下面的代码粘贴在head元素里(请注重它必需写在其他资本标签之前)。

<script>!function(a,b,c,d,e){function g(a,c,d,e){var f=b.getElementsByTagName("script")[0];a.src=e,a.id=c,a.setAttribute("class",d),f.parentNode.insertBefore(a,f)}a.Mobify={points:[+new Date]};var f=/((; )|#|&|^)mobify=(\d)/.exec(location.hash+"; "+b.cookie);if(f&&f[3]){if(!+f[3])return}else if(!c())return;b.write('<plaintext style="display:none">'),setTimeout(function(){var c=a.Mobify=a.Mobify||{};c.capturing=!0;var f=b.createElement("script"),h="mobify",i=function(){var c=new Date;c.setTime(c.getTime()+3e5),b.cookie="mobify=0; expires="+c.toGMTString()+"; path=/",a.location=a.location.href};f.onload=function(){if(e)if("string"==typeof e){var c=b.createElement("script");c.onerror=i,g(c,"main-executable",h,mainUrl)}else a.Mobify.mainExecutable=e.toString(),e()},f.onerror=i,g(f,"mobify-js",h,d)})}(window,document,function(){var a=/webkit|msie\s10|(firefox)[\/\s](\d+)|(opera)[\s\S]*version[\/\s](\d+)|3ds/i.exec(navigator.userAgent);return a?a[1]&&+a[2]<4?!1:a[3]&&+a[4]<11?!1:!0:!1},

// path to mobify.js
"//cdn.mobify.com/mobifyjs/build/mobify-2.0.1.min.js",

// calls to APIs go here
function() {
  var capturing = window.Mobify && window.Mobify.capturing || false;

  if (capturing) {
    Mobify.Capture.init(function(capture){
      var capturedDoc = capture.capturedDoc;

      var images = capturedDoc.querySelectorAll("img, picture");
      Mobify.ResizeImages.resize(images);

      // Render source DOM to document
      capture.renderCapturedDoc();
    });
  }
});
</script>

(请注重这段剧本不存在单点故障。假如Mobify.js载入失利,那末剧本会退出,你的网站依旧会一般载入。假如图片调解效劳器挂了或许你处于一个开辟环境中而且图片在外网不可接见,那末就会载入原始的图片。)

你也可以运用完全的文档。支撑上面代码的浏览器以下:一切的基于Webkit/Blink内核的浏览器,火狐4+,Opera 11+, and Internet Explorer 10+。

关于我们大多数的用例来讲,自动化调解img元素实在是太棒了。然则,就像演示的奥巴马的例子,art direction关于某些特定范例的图片是必要的。 那末我们怎样才继承运用picture元夙来支撑art direction而不是增加同个图片的6个版本呢?图象API一样会调解picture元素,也就是说你可以运用picture元素完成art direction,而把调解大小的功用交给API。

调解 <picture> 元素

固然差别的浏览器自动化调解图片大小是可行的,而自动化的art direction确切不能够。picture元素是最能够的计划来完成在差别的断点指定差别的图片,因为它内置的分支逻辑定义语法很硬朗(只管前文也提到了, srcN也供应了异常靠近的功用)。不过,为picture元素增加标记和为每一个图片建立6个版本让人觉得十分复杂:

<picture>
    <source srcset="responsive-obama-mobile.png 1x, responsive-obama-mobile-2x.png 2x">
    <source srcset="responsive-obama-512.png 1x, responsive-obama-1024.png 2x" media="(min-width: 512px)">
    <source srcset="responsive-obama-1024.png 1x, responsive-obama-1024.png 2x" media="(min-width: 1024px)">
    <source srcset="responsive-obama-2048.png 1x, responsive-obama-4096.png 2x" media="(min-width: 2048px)">
    <noscript><img src="responsive-obama-512.png"></noscript>
</picture>

当运用图象API和picture元素相结合, 代码标记显著简化了:

<picture>
    <source src="responsive-obama-mobile.png">
    <source src="responsive-obama.png" media="(min-width: 512px)">
    <img src="responsive-obama.png">
</picture>

这里的source元素会自动重写img元素(像前面的例子一样)。同时,注重上面的标记不须要运用noscript来阻挠第二次要求,因为捕获(Capturing)许可你保存标记的语义。

Mobify.js一样能用于已变动的picture元素,便于显式的定义差别的断点须要多宽的图片,而不再一览与装备的宽度。 举个例子, 你有一张平板电脑一半宽的图片,那末依据浏览器的最大宽度指定该图片的宽度所天生的图片,它会比实际须要的尺寸大一些:

《【译】运用Mobify.js让你的图片自动相应化》

为了处置惩罚这个题目,图象API可以改变picture标记,使得我们可以从新设定每一个source元素的宽度,而不是为每一个判断指定差别的src属性。比方,我们可以写成下面如许:

<picture data-src="responsive-obama.png">
    <source src="responsive-obama-mobile.png">
    <source media="(min-width: 512px)">
    <source media="(min-width: 1024px)" data-width="512">
    <source media="(min-width: 2048px)" data-width="1024">
    <img src="responsive-obama.png">
</picture>

注重谁人运用了data-src属性的picture元素,这里定义了一个高分辨率的原始图片作为一个出发点,这个图片会被用于其他断点的尺寸调解。

它在浏览器中是怎样事变的

  • 假如浏览器宽度介于0到511像素(比方一部智能手机), 那末运用responsive-obama-mobile.png (出于对art
    direction的斟酌)。

  • 假如浏览器宽度介于512到1023像素,那末运用responsive-obama.png,因为该媒体查询下source没有指定src。自动的决议宽度因为
    data-width没有指定。

  • 假如浏览器宽度介于1024到2047像素,那末运用responsive-obama.png,
    因为该媒体查询下source没有指定src。调解宽度为512像素,它被定义在data-width属性中。

  • 假如浏览器宽度为2048像素或更大,那末运用responsive-obama.png,
    因为该媒体查询下source没有指定src。调解宽度为1024像素,它被定义在data-width属性中。

  • 假如不支撑javascript,恢复为旧的img标签。

图象API会遍历一切的picture元素,并将它改变以下:

<picture data-src="http://cdn.mobify.com/mobifyjs/examples/assets/images/responsive-obama-mobile.jpg">
    <source src="//ir0.mobify.com/webp/400/http://cdn.mobify.com/mobifyjs/examples/assets/images/responsive-obama-mobile.jpg">
    <source src="//ir0.mobify.com/webp/400/http://cdn.mobify.com/mobifyjs/examples/assets/images/responsive-obama.jpg" media="(min-width: 512px)">
    <source src="//ir0.mobify.com/webp/512/http://cdn.mobify.com/mobifyjs/examples/assets/images/responsive-obama.jpg" media="(min-width: 1024px)" data-width="512">
    <source src="//ir0.mobify.com/webp/512/http://cdn.mobify.com/mobifyjs/examples/assets/images/responsive-obama.jpg" media="(min-width: 2048px)" data-width="1024">
    <img src="responsive-obama.jpg">
</picture>

Picture polyfill (包括在Mobify.js里)会被实行然后依据媒体查询挑选恰当的图片。当浏览器厂商支撑了原生picture后,它也能运转优越。

这里有一个运用已变动picture元素标记( the modified picture element ) 的例子,你可以看看。

不经由历程捕获的体式格局运用图象API

运用捕获须要将剧本写在head标签里,这会壅塞javascript的挪用而且会推延资本的初始化下载。该耽误的时刻长度在3G链接下也许为0.5秒(比方dns剖析和资本的捕获和下载),在4G或wifi下耗时会相对少些,大约有60毫秒的耽误。这个耽误的小价值换到的是易于运用,和向下兼容以及语义化。

不经由历程捕获的体式格局运用图象API来防止壅塞javascript要求,你须要将一切img元素src属性改成x-src属性(你也可以恰当的增加noscript编辑来检测浏览器javascript的支撑状况)而且在head标签内粘贴下面的异步剧本:

<script src="//cdn.mobify.com/mobifyjs/build/mobify-2.0.1.min.js">
<script>
    var intervalId = setInterval(function(){
        if (window.Mobify) {
            var images = document.querySelectorAll('img[x-src], picture');
            if (images.length > 0) {
                Mobify.ResizeImages.resize(images);
            }
            // When the document has finished loading, stop checking for new images
            if (Mobify.Utils.domIsReady()) {
                clearInterval(intervalId)
            }
        }
    }, 100);
</script>

这段剧本会异步载入Mobify.js ,当载入完成后,最先一般载入图片就像载入html文档一样。

在WebApp中运用图象API

假如你正在运用一个客户端javascript MVC框架,比方Backbone 或 AngularJS,你依旧可以运用Mobify.js的图象API。起首,将Mobify.js库包括到你的app中:

<script src="//cdn.mobify.com/mobifyjs/build/mobify-2.0.1.min.js"></script>

然后,运用Mobify.js文档中列出的要领重写图片的URL。

Mobify.ResizeImages.getImageUrl(url)

该要领接收一个相对URL然后返回图象调解后的URL。最简朴的体式格局将图片传入这个要领是经由历程建立 模板辅佐函数(template helper) (比方, {{image_resize ‘/obama.png’ }} 在 Handlebars.js)实行了getImageUrl 要领来自动天生图象的URL。

在后端运用你的图象尺寸调解(Image-Resizing)

图象已被Mobify’s Performance Suite 尺寸调解效劳器 调解了,它支撑自动化调解WebP,CDN缓存等等。不过每月免费调解的数目有一个默许的限定,不过别忧郁,假如你对流量的需求比较大,那末高声喊Mobify 一声,我们会尽量的给予帮助。该API也许可你运用差别的图象调解效劳,比方Sencha.io Src,或是你本身的后端效劳。

浏览器厂商怎样能更好的支撑响应式图象?

Webkit团队近来已完成了src-set属性,那末Blink和Gecko也将在不久完成。这是准确道路上行进的一大步,这意味着浏览器厂商已严峻注重了响应式图象的题目。然则,它不能处置惩罚 art direction题目,也不能防止天生多个分辨率版本文件的步骤。

开辟社区近来也一同议论了响应式图片的题目。个中有一个风趣的提案是Ilya Grigorik提出的客户端提示,该发起包括在每一个要求头部发送装备属性比方DPR和高度。我喜好这个计划,因为它能让我们继承运用img标签,然后在我们须要建立分支逻辑完成art direction只须要运用picture(或srcN)即可。只管增加分外的HTTP头和运用内容协商来处置惩罚这个题目已被证实有用,对与具有不计其数图象的网站来讲,运用该计划来定位图象生怕不太可行。经由历程效劳层或代办重写图象,可以处置惩罚这个题目,不过这两张体式格局都能够被设置的有题目。在我看来,假如在客户端能更好的掌握资本加载,那这些个题目我们是可以处置惩罚处置惩罚的。

假如开辟者更好的掌握了资本的加载,那末响应式图片应当会被看成一个简朴的题目来处置惩罚。之所以云云多的响应图象处置惩罚计划是基于代办练习,是因为在文档抵达浏览器之前,图象必需被重写。这是对预加载器尝试尽快下载图片行动的顺应。不过代办的计划能够在安全性和扩大性方面会有很多题目,假如我们有一个简朴的体式格局来和预加载器交互,那末很多基于代办的计划就显得冗余了。

那末怎样在更好的掌握资本加载的同时,依旧享用预加载器带来的优点呢?这里症结点是我们不愿望简朴的封闭预加载器-它并行下载的才能是一个庞大的成功,而且已被浏览器完成了。(请注重捕获API不会壅塞并行下载。)个中一个要领是供应一个beforeload事宜,该事宜在资本载入之前触发。该事宜在safari浏览器中经由历程一个扩大就可以完成了,在某些浏览器中也可以运用,不过容量有限。假如如今可以运用该计划的话,那末就不再须要捕获了。下面是一个运用beforeload事宜的一个基本例子:

function rewriteImgs(event) {
    if (event.target === "IMG") {
        var img = event.target;
        img.src = "//ir0.mobify.com/" + screen.width + "/" + img.src;
    }
}
document.addEventListener("beforeload", rewriteImgs, true);

症结的应战在于以某种体式格局在实行构图轮回时刻(in the main rendering loop)让预加载器和javascript交互优越。有一个当前正在浏览器中开辟的一个新系统,叫做 Service Worker,
它的目标是许可开辟者截获收集要求来辅佐构建离线web运用。然则,当前的完成不许可阻拦初始要求。这是因为载入一个分外的剧本会壅塞其他资本的载入-不过我置信这个状况会改变,比方经由历程不捐躯机能的内联剧本的体式格局。假如你有以下的需求,可以斟酌运用 Mobify.js 来自动处置惩罚响应式图片:

总结

响应式图片方面的题目有很多的处置惩罚计划,事变自动化的同时依旧可以art direction的计划驱动将来的Web开辟的处置惩罚计划。

  • 只须要为每一个资本供应一份高版本的图片,让API完成供应基于装备前提(宽度,WebP支撑状况等等)的小图片。
  • 每一个图片之发作一次要求。
  • 须要100%的语义和向下兼容旧标记而且不须要改变后端(运用捕获的状况)。
  • 已最先运用picture元夙来自动调解大小,只专注与运用它来完成art direction。

原文 Automate Your Responsive Images With Mobify.js
作者 Shawn Jansepar

    原文作者:王铁手
    原文地址: https://segmentfault.com/a/1190000000359160
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞