背景
众所周知,retina屏的设备像素比是2,而普通屏幕像素比为1,对于图片这种位图像素已定的资源,如果不加以处理的话,要么全都用1倍图,在retina屏上观看就会模糊;要么都是用2倍图,那么在普通屏幕上浏览的时候就会白白浪费流量消耗下载速度。
简单介绍下css像素和位图像素的区别:
- 无论是retina屏还是普通屏幕,图片展示的区域大小是相同的,这也就是css像素与设备无关。
- retina屏一个1x1的css像素区域对应着2x2的物理像素,也就是每个css像素宽的区域,在retina屏上是可以再分成两半来显示的,即dpr=2的retina屏上的最小css像素分辨率是0.5px。
理论上,一个位图像素是对应一个物理像素的时候展示完美:
1、假如在retina屏使用1倍图:也就是1个位图大小的区域去用4个物理像素渲染,被分割的位图只能就近取色,就会导致图片显示模糊;
2、同样的,如果在普通屏幕上使用2x图,那么就会一个物理像素对应4个位图像素,就会通过一定算法,给该物理像素一个近似的值,(downsampling过程),图片不会模糊,但会缺失一些锐度。
目前主流方案(使用二倍图):
img{
max-width:100%;
height:auto;
}
而图片展示的情况在如今也是应用的越来越多,所以要找到两者完美匹配的方法,也就是——响应式图片。
CSS解决方案——媒体查询
最大缺点:只能用于css,所以也就限定了只有background中的图片可以使用此方法。
简介一下:
@media
only screen and (-webkit-min-device-pixel-ratio:2),
only screen and (-min-moz-device-pixel-ratio:2),//版本低于16的Firefox
only screen and (min-resolution:2dppx),
only screen and (min-resolution:192dpi){
...
}
像七牛这样专业的图片处理应用都可以根据需求生成一倍图,这样对于不同分辨率的显示器,也可以使用不同分辨率的图片。另外的不足是使用媒体查询多了不少代码,个中利弊,具体情况下再权衡吧。
resolution :定义设备的分辨率。
dppx:也是设备像素比,和dpr一样。
dpi:(Dots Per Inch)每英寸点数。
1dppx=96dpi
【小科普:1参考像素即为从一臂之遥看解析度为96DPI的设备输出即1英寸96点)时,1点(即1/6英寸)的视角。 】
另外,在最新的以webkit为内核的浏览器中,支持支持CSS4的background-image新规范草案image-set,在移动端也勉强可以接受吧。
selector {
background-image: url(no-image-set.png);
background: image-set(url(foo-lowres.png) 1x,url(foo-highres.png) 2x) center;
}
不支持image-set的浏览器会解析background-image中的背景图像;支持image-set的浏览器就会根据是否为retina屏选择相应的背景图,因此这个方案是可以实现向下兼容的。
HTML解决方案——srcset+sizes+w标识符
这是HTML5推出的属性,srcset可以根据显示器分辨率智能加载最佳显示的图片。
<img class="image" src="mm-width-128px.jpg"
srcset="mm-width-128px.jpg 128w, mm-width-256px.jpg 256w, mm-width-512px.jpg 512w"
sizes="(max-width: 360px) 340px, 128px">
srcset :指向提供的图片资源,为用户提供了一种内嵌简单的分辨率媒体查询功能;
sizes : 指定图片宽度,不能使用百分比,可使用:
px,
vw(100vw就是占满父容器宽度,所以要求图片居中宽度为百分比的地方可以使用vw单位,如 sizes=80vw),
calc运算(适用于两边距离固定的情况,如sizes="calc(100vw-20px)"),
媒体查询(如sizes="(min-width:360px) 340px,128px")。
而且最重要的是,sizes属性产生的初衷就是可以在html中实现简单的媒体查询功能,来适应越来越大规模的响应式网站开发。
那么w是个啥?
w是一个衡量宽度的标识符,一定要对应图片的真实宽度,这会使得浏览器正确的选择图片,如果w值和图片宽度不对应时,实际渲染是会有问题的。
拿这段代码来说:
<img class="image" src="test-240.jpg"
srcset="test-240.jpg 240w, test-480.jpg 480w, test-720.jpg 720w"
sizes="240px">
sizes=240px,也就是图片宽度设置为了240px,那么:
当该屏幕dpr==1时,就会选用test-240.jpg;
dpr==2时,可渲染的位图像素宽度就变为了480px,也就选用了test-480.jpg;
dpr==3时,能渲染的位图像素宽度变为了720px,那么浏览器去选择最适合的图片,也就是test-720.jpg;
关于w值设置如果不正确,会出现什么后果,我在这篇文章中写了详细的案例。
现代浏览器对该属性的支持是越来越多了,这个方案应该会是个潮流。
在移动端andriod browser的支持度实在是太差劲了,PC端对于一些fashion的网址试一试。
javascript解决方案
- 基于jquery的HiSRC插件,可以基于网速和是否为retina屏来显示图片。
<div class="hisrc">
<img src="placehold.it/200x100.png" data-1x="placehold.it/400x200.png" data-2x="placehold.it/800x400.png">
</div>
然后调用hisrc的方法
$(document).ready(function(){
$(".hisrc img").hisrc();
})
官方文档是这样介绍HiSRC如何工作的:正常情况下会直接加载src中的资源;如果网速较好就会加载data-1x中的资源替代原来src的文件;如果设备像素比又比较高的话,就会加载data-2x中的资源代替原来的src中的图片。
它还提供选项允许我们设置一个网速基准。这个html的结构让我不由得想起了lazyload的解决方案,这俩真的是太相似了,我们完全可以给src中放一个统一的占位图,然后再去选择加载适合浏览器展示的图片。
另外还有用于rails的gem包:hisrc-rails.
所以也可以写成这样
responsive_image_tag("http://placehold.it/100x100", :'1x' => "http://placehold.it/200x200", :'2x' => "http://placehold.it/400x400")
对于这个方案,个人觉得在工程上应用是可以期待的,因为图片都放在七牛那儿,可以图片上传成功后从2倍图中处理出1倍图,然后再向img标签中添加data-1x,data-2x这样的属性,不过呢,这好像把工作几乎全部添加给了后台的哥们儿,想到这儿,好像应用的难度瞬间增大了呢。。。
- picturefill方案,依赖picturefill.js这个脚本文件,并且它还对结构有一定的要求,对格式有特定的要求,最开始这个来自于对<picture>的支持。
<picture>
<source srcset="smaller.jpg, smaller_retina.jpg 2x" media="(max-width: 768px)">
<source srcset="default.jpg, default_retina.jpg 2x">
<img srcset="default.jpg, default_retina.jpg 2x" alt="My default image">
</picture>
看到该结构要写这么多代码,多少就会产生一点心理抗拒,但是呢本着技术进步的态度,还是再进一步研究下。
由于picture元素是html5的新产物,兼容性上还不是特别好,要想大规模使用可以配合picturefill.js,另外现在picturefill也支持有srcset属性的img。
这里有picturefill在应用<picture>的页面中存在的一些问题 。
//主要是IE9和安卓2.3上存在一些问题,不过IE9通过hack方法也是可以挽救的。
最后,两句话介绍一下服务端解决方案:
Adaptive Images:最大缺点基于PHP和Apache。它是拦截通过服务器的图片请求来生成图片,如果图片是通过第三方的分网网络的也就用不上了。
综上
不过既然picturefill也支持srcset,那么比较srcset属性和picture元素,浏览器对srcset属性的支持是更好的。所以srcset+sizes+w的img元素配合picturefill.js效果应该会不错。只是很可惜,这样的应用案例还没有找到。不过即使picturefill.js不能完美配合srcset方案,仅仅使用srcset+sizes+w就可以应付主流现代浏览器了,重要的是,这个方案完全也是向下兼容的啊。
参考:
http://www.tuicool.com/articles/ZraMfa
http://www.zhangxinxu.com/wordpress/2014/10/responsive-images-srcset-size-w-descriptor/
http://www.w3cplus.com/responsive/understanding-responsive-web-design-how-to-manage-images.html
http://scottjehl.github.io/picturefill
https://www.ze3kr.com/2015/08/using-srcset/#section-6