Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[译] 剖析responsive image #5

Open
riskers opened this issue Sep 14, 2015 · 4 comments
Open

[译] 剖析responsive image #5

riskers opened this issue Sep 14, 2015 · 4 comments
Labels

Comments

@riskers
Copy link
Owner

riskers commented Sep 14, 2015

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

原文地址

剖析responsive image

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

尺寸固定,不同屏幕密度

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

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

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

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

  • srcset里的每一项都是<url> <density>x结构 ,就像cat-2x.jpg 2x
  • srcset里项目的顺序并不重要
  • 如果你没有声明width/height,浏览器会按照屏幕密度展示它本身原始的width/height。 比如2x资源被匹配到了,它会被渲染成本身的 50%width和 50%height
  • 提示一下,如果在3x设备像素比的设备上浏览器渲染的是1x的图片,可能是因为糟糕的网络环境

案例

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

译者案例

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

尺寸和屏幕密度都不同

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

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

  • 不同尺寸图片的地址
  • 每张图片的宽度
  •   `<img>`的宽度
    

最后一点是特别困难的,因为图片开始下载是在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的这张图。

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

  • srcset里的每一项是<url> <width-descriptor>w,比如panda-689.jpg 689w
  • srcset里每一项的顺序没有影响
  • 如果srcset包含了一个宽度描述符(w),则src会被那些支持srcset的浏览器忽略掉
  • sizes里的每一项是<媒体查询> <图片宽度>形式,除了最后一个仅仅是<图片宽度>
  • sizes里的宽度单位都是px
  • 浏览器使用sizes里的第一个匹配到的媒体查询,所以sizes里的顺序是很重要的
  • 和上面一样,浏览器下载一个低分辨率图片可能是因为糟糕的网络

如果你没有指明<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>
  • 媒体查询<source>元素上总是被服从的
  • 媒体查询是基于窗口的宽度,不是<img>
  • 第一个匹配到的<source>会被使用,所以顺序很重要
  • 如果没有匹配到<source>,则<img>被调用
  • <img>必须出现在<source>后面
  • <source>不支持src,但是支持srcset

一旦<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>

  • type属性是mime类型
  • 你可以有很多种资源和混合typemediasrcset甚至是sizes取创建一些惊奇的东西

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


案例

我的总结

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

扩展阅读

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

译者推荐文章

与本文结构类似的文章:

补充文章:


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


@riskers riskers changed the title [译] 剖析responsiveimage [译] 剖析responsive image Sep 15, 2015
@riskers riskers added and removed labels Sep 15, 2015
@riskers
Copy link
Owner Author

riskers commented Sep 16, 2015

有人在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
Copy link

0326 commented Sep 20, 2015

很详细,保持关注!

@riskers
Copy link
Owner Author

riskers commented Sep 20, 2015

@0326 那就请订阅一下吧 😄

@byr-gdp
Copy link

byr-gdp commented Sep 25, 2015

学习! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants