响应式图片

3,160 阅读9分钟

当我们不考虑图片所耗的流量,用户对于某个含有图片的页面的体验时,通常会这样插入一张图片:

<img src="example.jpg" width="100" height="100" />

在chrome显示如下:

根据设备像素比动态选择图片源

在手机端,大图高清图加载速度慢,耗流量多,且在像素密度低的设备上加载高清图简直是浪费好吗!再好的高清图也只能显示成劣质图片。。。

如果我们能够根据设备屏幕的像素密度,宽度选择适合该设备的图片资源,是不是一件很美好的事情!

那么,现在,有这样两个属性可以完成这个小愿望哦!

srcset
含义:提供在不同场景下供user agent(第7条)选择的图片源
值: 为多个图片候选字符串(image candidate string)图片候选字符串(术语第29条)之间由“,”分隔


sizes
含义: 根据设备的尺寸动态设置<img>元素的大小
值: media_condition(术语第30条) [image_width], [default_image_width]
选择规则: 执行过程中的第一个media_condition为true,则使用对应的image_width,若都为false,则使用default_image_width

例1

两张图片,一张普通图(500*444),一张高清图(1000*888)

普通图的尺寸详细信息如下:

水平/竖直分辨率均为96dpi(1dpx=96dpi)的情况下,尺寸为500*444,说明该图片的位图宽度为500,位图高度为444,即在设备分辨率为1的设备上,图片尺寸为500*444。


<body>
   <h2>different images</h2>
   <img srcset="example.jpg 500w, example-HD.jpg 1000w" sizes="(max-width:800px) 80vw,(max-width:1500px) 50vw, cal(30vw-100px)" alt="a house with a big courtyard">
</body>


在chrome的调试模式下,添加自定义设备,并运行

  • 自定义设备500*1

设备大小500*700,设备像素比例为1

chrome运行结果:

视图窗口宽度为500px,因此图片的宽度会选用80vw档,为500*80%=400px

因为图片的宽度为400px,设备像素密度为1,那么图片所需像素宽度为400*1=400w,chrome浏览器从srcset中选择了普通图

虽然视图窗口宽度为500px,但在实际运行结果中宽度却只有200px,图片宽度只有160px。这是为什么呢?

在<head>里加入了一段js代码,检查了chrome的设备像素比。

window.onload=function(){
		alert(window.devicePixelRatio);
	}

发现当前chrome的像素设备比为2.5

因为这个自定义设备是chrome模拟出的一个虚拟设备,这段代码实际上还是运行在chrome上,因此视图窗口的css pixel为500*1/2.5=200px。

  • 自定义设备500*2

设备大小500*700,设备像素比例为2

chrome运行结果:

视图窗口宽度为500px,因此图片的宽度会选用80vw档,为窗口的80%,

因为图片的宽度为400px,设备像素密度为2,那么图片所需像素宽度为400*2=800w,chrome浏览器从srcset中选择了最为合适的高清图。

  • 自定义设备1000*1

设备大小1000*700,设备像素比例为1

chrome运行结果:

视图窗口宽度为1000px,因此图片的宽度会选用50vw档,为窗口的50%,

因为图片的宽度为500px,设备像素密度为1,那么图片所需像素宽度为500*1=500w,chrome浏览器从srcset中选择了最为合适的普通图。

  • 自定义设备1000*2

设备大小1000*700,设备像素比例为2

chrome运行结果:

视图窗口宽度为1000px,因此图片的宽度会选用50vw档,为窗口的50%,

因为图片的宽度为500px,设备像素密度为2,那么图片所需像素宽度为500*2=1000w,chrome浏览器从srcset中选择了最为合适的高清图。

  • 设备模式中的Responsive

chrome运行结果:

视图窗口宽度为1904px,因此图片的宽度会选用默认档,为528px。

图片宽度528px,设备像素密度未知,chrome浏览器从srcset中选择了高清图。

艺术指导配合设备像素比动态选择图片源

上面的做法可在一定程度上调节图片大小,节省手机流量,然而所有设备上呈现的图片内容都是一样的,没有针对性。如果我希望在大屏幕上呈现整张图片,在手机端却只想展示关键部分,该怎么做呢?或者当手机处于横屏时显示宽图,当手机处于竖屏时显示普通图,该怎么做呢?

这需要艺术指导!(是不是跟没说一样。。。)

想要做到这点,需要用到<picture>元素及<source>元素。

例2

四张图:手机普通图(250*199,图片上标注 normal phone),手机高清图(500*399,图片上标注 HD phone),电脑普通图(500*444,图片上标注 normal),电脑高清图(1000*888,图片上标注 HD)

<!DOCTYPE>
<html>
<head>
<style>
	*{
		margin-left:0;
		margin-right:0;
	}
</style>
</head>
<body>
   <h2>different images</h2>
   <picture>
   		<source media="(max-width:500px)" srcset="example-phone.jpg 500w,example-HD-phone.jpg 1000w" sizes="100vw">
   		<source media="(max-width:1000px)" srcset="example.jpg 500w,example-HD.jpg 1000w" sizes="50vw">
  		<img src="example.jpg" alt="a house with a big courtyard">
   </picture>
</body>
</html>


在chrome的调试模式下,添加自定义设备,并运行

  • 自定义设备500*1

chrome运行结果:

视图窗口宽度为500px,故chrome选择第一个<source>提供的图片源。

图片的宽度为100%的视图窗口,应该为500px,又设备像素密度为1,那么图片所需像素宽度为500*1=500w,chrome浏览器选择了example-phone.jpg。

注:虽然example-phone.jpg的实际宽度只有250px,但chrome在真正将图片抓取(fetch)下来之前它是不知道这个实际宽度的,它只知道根据开发人员设置的sizes值及视图窗口去定图片的宽度,然后选择合适的图片源去展示出来。

  • 自定义设备500*2

设备大小500*700,设备像素比例为2

chrome运行结果:

视图窗口宽度为500px,故chrome选择第一个<source>提供的图片源。

图片的宽度为100%的视图窗口,应该为500px,又设备像素密度为2,那么图片所需像素宽度为500*2=1000w,chrome浏览器选择了example-HD-phone.jpg。

  • 自定义设备1000*1

设备大小1000*700,设备像素比例为1

chrome运行结果:

视图窗口宽度为1000px,按理说chrome应该选择第二个<source>提供的图片源,为什么选择了手机高清图

好奇怪。。。待我日后慢慢研究。

  • 自定义设备1000*2

设备大小1000*700,设备像素比例为2

chrome运行结果:

结果竟然与上面的一样,心酸,不解释。

  • 设备模式中的iphone8

chrome运行结果:

iphone宽度375px,为什么<html>宽度为980px。。。

视图宽度按980px算,那么选择第一个<source>,图片宽度为490px,这是正确的。

iphone8设备像素比(第33条)为3,那么图片的物理像素宽度为490*3=1470w,那么选择高清图是合适的。

例3

两张图,一张横屏图(example-landscape.jpg),一张竖屏图(example-vertical.jpg)

<body>
   <h2>different images</h2>
   <picture>
   		<source media="(orientation:landscape)" srcset="example-landscape.jpg">
  		<img src="example-vertical.jpg" alt="a house with a big courtyard">
   </picture>
</body>

在chrome上模拟iphone8运行

根据条件orientation可选择合适的图。

配合图片格式

使用<source>时结合浏览器支持的图片格式进行更精确的选择

例4

两张图:house.svg和house.png

<body>
   <h2>different images</h2>
   <picture>
   	<source type="image/svg+xml" srcset="house.svg">
  	<img src="house.png">
   </picture>
</body>

在chrome上运行

chrome支持svg格式,采用的是house.svg

准备好图片的文本备用方案

当少数用户因为不能看见图片不得不采取语音的方式浏览网页时,给图片设置文本就显得至关重要。

<img>有个属性alt,就是专门使用文本的方式去传达图片的内容及目的。

看下面这张图:

我们可以用如下img元素去描述它:

<img src="pipechart.gif" alt="Browser Share: Internet Explorer:25%, Firefox:40%, Chrome:25%, Safari:6%, Opera:4%">

我们在设置alt属性值时,应尽可能描述出图片的内容。如果图片传达的内容过多,使用alt属性不太方便时,可使用longdesc属性,不过这个属性过时了,但目前我还没发现有更好的替代品。

小结:srcset属性配合sizes可帮助我们选择尺寸不同但内容相同的图片,让图片加载更快,流量更省;而<picture><source>元素则可让我们针对不同的设备终端显示不同的图片,定位用户更精准,当然,这也可配合srcsest属性使用;针对不同的设备,支持的图片格式可能不一样,配合图片格式使用<picture><source>,在图片解压缩方面性能更好;最后,设置好图片的alt属性,以备不时之需。(文中留下的坑日后慢慢研究。。。心酸中)