riskers / blog

:pencil2: 博客写在 Issues 里
http://riskers.github.io/
MIT License
1.13k stars 96 forks source link

[译] 剖析responsive image #5

Open riskers opened 9 years ago

riskers commented 9 years ago

之所以会翻译这篇文章是因为我昨天看到@勾三股四的这篇微博,里面推荐的文章就是下面我要翻译的。因为自己一直对响应式图片这个技术很关注,但是一直没有一个很好的总结机会,今天趁着翻译这篇文章总结了,这是本人翻译的第一篇文章,有错误的地方请指出。

原文地址

剖析responsive image

最近对responsive image有一些感悟然后赶紧记下来免得忘了。下面就是我的感悟:

尺寸固定,不同屏幕密度

如果你是用像素来固定图片尺寸,又想在不同屏幕密度屏幕上实现响应式图片,可以这样:

<img width="320" height="213"
    src="cat.jpg"
    srcset="cat-2x.jpg 2x,cat-3x.jpg 3x">

它可以正常运行在所有现代浏览器上,而且在不支持srcset的浏览器也可以降级到src

有一些规则是上面图片所没有提到的:


案例

这个案例使用的是3张一样的图片,只是尺寸不一样,这样我们很难看出区别。所以译者在这里换了这几张图,然后在Chrome中模拟手机调试,更换分辨率,应该就很明显了。

译者案例

这种方法因为要人为匹配设备像素比,所以1x2x3x4x等等,这样HTML就会太臃肿,所以有了下面的新方法。

尺寸和屏幕密度都不同

不同宽度的图片在响应式站点里是很常见的。在这篇博客里,图片内容都是占据了文章100%的宽度,但是文章的宽度并不总是窗口宽度的100%。

为了让浏览器匹配到正确的图片,我们需要知道:

最后一点是特别困难的,因为图片开始下载是在CSS解析之前的,所以<img>的宽度不能从页面布局那得到。

<img src="panda-689.jpg"
    srcset = "panda-689.jpg 689w,
                panda-1378.jpg 1378w
                panda-500.jpg 500w
                panda-1000.jpg 1000w"
    sizes = " (min-width:1066px) 689px,
                (min-width:800px) calc(75vw-137px) ,
                (min-width:530px) calc(100vw-96px) ,
                100vw" >

通过srcset属性,浏览器知道了哪些图片可用以及这些图片的宽度。 通过sizes属性,浏览器知道了<img>相对于一个已知宽度窗口的宽度。 这样,浏览器就可以匹配最佳资源加载了。

你不再需要说明屏幕密度,浏览器自己会辨别。如果浏览器窗口宽度是1066px甚至更大,<img>会被定为689px。在1x设备浏览器上会下载panda-689.jpg,但是在2x设备浏览器上将会下载panda-1378.jpg

这里感觉作者并没有解释清楚 sizessrcset的工作原理(参照下面的译者案例来看)。

首先,是关于sizes的理解: 比如当前窗口800px,那么sizes会匹配到(min-width:800px) calc(75vw - 137px) ,则这个<img>对应的宽度就是800px*0.75-137px=463px。这个宽度的设定相当于

<img src="..."  width="463" />

知道了<img>width,然后再看srcsetw: 在dpr1的时候,463px对应463w,查找srcset,找到500w适合它,就显示500的这张图。 在dpr2的时候,463px对应926w,查找srcset,找到1000w适合,就显示1000的这张图。

一些规则是上面没有提到的:

如果你没有指明<img>的宽度,浏览器也会正常解析。对sizes精确设置,但是一个不是很确切的宽度也很好。比如

sizes="(min-width:1066px) 689px ,
    (min-width:800px) 75vw,100vw"

挑选哪些图片资源放在srcset里是很困难的,我也没有完全掌握技巧。在上面的例子里,我设置了一个最小尺寸(注:原文中是最大)(689px),然后给2x设备设置刚才的两倍尺寸(1378px)。另外两个设置是在这两个值中间任意取的。我没有设置更小的宽度比如320px,因为在这一情况下的屏幕密度是2x或者更高。

srcset + sizes 在 Chrome、Firefox和Opera中都兼容。至于其他浏览器,也会很安全地回退到src属性。不用等待很久,WebKit nightly 和 下一个稳定版本的Edge就会很好地支持它。

WebKit nightly是WebKit的mac port,对于Safari就像Chromium对于Chrome

开发者需要了解的WebKit


案例

原文中<img>有一个内联样式width:100%,一开始没有注意到的话还以为没有变化呢。上面的案例已经修改过了 -。-

还是因为作者使用了内容相同,尺寸的图片,所以我换了图片重新做了一个例子:

译者案例

这种新方法的srcset用来指向提供的图片资源,没有上面方法的1x2x,这个都交给浏览器。例子中就指向了3个尺寸图片。

sizes用来表示尺寸临界点,用媒体查询定下图片的实际宽度。

不同宽度、分辨率和艺术指导

和之前的例子类似除了框架的不同宽度的变化。它允许你集中精力对付更小的宽度。

一旦<source>或者<img>被选中,srcsetsizes属性就像之前的例子一样解析。

艺术指导:剪裁图片内容来适应特定环境,任何时候我们裁剪或是修改图片来适应一个断点(而非简单缩放),都是一种艺术指导。

可以看出来,艺术指导比之前的srcset+sizes又多了一层维度:source的媒体查询。

<picture>元素在Chrome、Firefox和Opera中兼容良好,在其他浏览器可以回退到<img>。而下一代的Edge也可能会支持

--

案例

不同类型

这个方法可以让你有更优化的方式去提供给支持它们的浏览器。

<picture>
    <source type="image/webp"
        srcset="snow.webp">
    <img src="snow.jpg">
</picture>

它在Chrome、Firefox和Opera上兼容良好,其他浏览器还可以回退到<img>


案例

我的总结

  1. 对于响应式图片我们一开始使用x方式,但是这种方法有缺点:
    • PC端和移动端无差别对待:它们都有1x2x3x屏幕,这样 iPhone 可能加载一张2x的图片,甚至以后还会加载出3x4x的图片!
  2. 使用w方式就没有上面的问题了,一切都交给浏览器自动判断自动加载
  3. 艺术指导就比w方式多了一层维度,可以更加精准地加载图片

扩展阅读

希望上面的文章能够对各种用例起到参考作用,你可以继续看看下面的文章:

译者推荐文章

与本文结构类似的文章:

补充文章:


向我捐助 | 关于我 | 工作机会


riskers commented 9 years ago

有人在segmentfault

html5标签属性实现的响应式与css实现的有什么不同点?

上面说过:

比如当前窗口800px,那么sizes会匹配到(min-width:800px) calc(75vw - 137px) ,则这个<img>对应的宽度就是800px*0.75-137px=463px。这个宽度的设定相当于

<img src="..." width="463" />

而CSS的width只是"显示"的表示,就像上面的 463px 的图片,可以用css设置width为1000px,也可以设置成100px。

但是响应式图片的width是指的是在html标签中设置的width。 利用sizes可以"动态"地响应变换这个 width ,这才是精髓 。

举个例子说吧,比如网页上有一个占据窗口100%宽度的banner图片,是960 * 480的。

用CSS控制很简单,width:100%就行了,这样不管在什么设备上都"看起来"ok。但是让手机加载一张这么大的图是很慢的,不可能因为"看起来"只有320px(比如iPhone4)就会把图片的sizes(这里的sizes指的不是宽/高,是指kb)降低。

响应式图片就不同了,它在HTML加载的时候就可以根据sizes判断出它应该渲染出来的宽度,根据srcset判断加载的图片,这样在手机上就真的可以加载出 宽度320px的图片。

0326 commented 9 years ago

很详细,保持关注!

riskers commented 9 years ago

@0326 那就请订阅一下吧 :smile:

byr-gdp commented 9 years ago

学习! :)