移动端适配方案进阶
Web页面做移动端适配,就是在不同尺寸的手机设备上,页面“相对性的达到合理的展示(自适应)”或者“保持统一效果的等比缩放(看起来差不多)”。有几个要点必须要掌握,一个是不同尺寸,一个是清晰,还有一个是合理。为什么强调这几个词当然是有原因的。
一、目标
1. 页面布局总是按照一定规则来进行的。但是移动设备却是多种多样的,屏幕尺寸大小不同,分辨率不同,像素比不同,宽高也不同(相应的概念会在后面介绍)。所以要让一套代码适应所有设备,是最棘手的。、
2. 要保证清晰度,小屏手机和大屏手机用同样的图片,通过缩放效果显示的大小比例是一致的,但是图片放大会失真,高清图缩小预览又浪费。这就需要综合考虑情况了。
3. 所谓合理展示,指的是不论什么设备都能有原设计稿一样的视觉和体验效果。如果单纯的按照固定的像素px来设置宽高,结果会怎样。要么小屏手机出现滚动条,要么大屏手机有留白。虽说是原样输出,但这并不是设计稿的效果。人家设计稿是全屏完美展示,不能到手机上变成半屏或两屏了。所以说还原设计稿可以理解成等比例缩放。
二、思考
我们的目的搞清楚了,但是还是不得不先泼一泼冷水。首先,没有绝对完美的适配方案。不可能让所有设备真正100%还原设计稿。因为设备的宽高比例就不尽相同五花八门,光这一点就没办法解决,比如说你想用同一张图片给正方形和长方形做壁纸,总有一个会被拉伸或是留白。所以目前通用的原则是文字流式,控件弹性,图片等比缩放。借用万能网络上图片展示下效果。
有了目标和大致想法接下来差不多上方案了,为了更好讲解,还得科普几个知识点。
三、基本概念
屏幕尺寸(inch):手机设备的对角线长度,比如iphone5为4英寸。
屏幕宽高比:手机的高度与宽度的比例 为16:9
物理像素(px): 显示器(手机屏幕)上最小的物理显示单元,比如iphone5的物理像素是640*1136
像素密度(PPI): 表示沿着对角线,每英寸所拥有的物理像素(Pixel)数目,值越低颗粒感越强,超过300人眼很难分辨
设备独立像素|密度无关像素|逻辑像素(px): 可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css像素),然后由相关系统转换为物理像素。比如iphone5的物理像素是320*568
像素比(pdr): 物理像素和设备独立像素的对应关系,设备像素比 = 物理像素 / 设备独立像素,比如iphone5的像素比是2。
以上概念如果一下接受不了自行百度吧。在这里主要解释下pdr,原来的显示设备的pdr都是1,后来引入了高清屏有了retina,这个pdr就出现了。当然是值越高,显示效果越清楚,同时意味着用css控制某个像素的时候,实际上控制的是成倍的物理像素。最简单的例子是用Iphone5截个图,虽然css下最宽只有320px,但是把图片放到电脑上就成了640px了。
四,深入了解适配下的高清问题
用多大的图片才能清晰?
如果在pdr为1的情况下,要显示100*100的图片,用50*50,100*100还是200*200的图片。当然我们都能理解50*50肯定是要排除的。不过,原因是什么我们还需要讨论一下。换个更形象的说法,要用要求的红黄颜料填满2个坑,是要用一种颜料还是2种还是4种。如果用一种颜料同时显示红与黄的效果,那么只能把两种颜料先混合再倒入,结果肯定会失真;如果用两种,分别用红和黄倒入,那么就泾渭分明;如果用4种呢,就得压缩一半塞进去,也就是说红和黄已经被压缩了一半,还会渗进其它颜色才填满。这个时侯,显示效果会失去锐度。所以不论给的图片大了还是小了都不会模糊。
但是好多设备不是单单的pdr为1,如果等于2的时候,要显示100*100的图片,就需要200*200的图片;如果pdr为3,就要引入300*300的图片,同样有更多像素比的设备,不可能一一满足,因此普通做法是提供2x,3x图片。
五、适配方案
终于要讲到方案了,上面也讲到了要实现自适应就是等比例缩放。因此我们想到三种方案。
一,按百分比设置宽高。可能实现适配效果,缺点是会出现拉伸,模糊,因为设备宽高比不同,高度很难用百分比控制。
二,viewport缩放
在页面内可以设置viewport的scale
属性来控制页面显示比例。类似于放大缩小图片,通过计算设备宽度与设计稿的比例来得出缩放的倍数,最终实现适配效果。为了适配大多数设备并保证清晰度要采用更大分辨率的设计稿,感觉有些浪费资源。
三、rem相对单位
因为rem是相对单位,它会以Htm的font-size的大小为基数来计量长度。所以计算设备屏幕宽度与设计稿的比例来动态设备html的font-size,。这样就能在不同设备上等比例来显示。相当于先把屏幕宽度等分成固定的份数,然后再以份数作为单位计量。
其实现在的适配方案不外乎这么几种,尤其第三种操作起来很方便(后面会附上代码)。不过,阿里团队为了追求清晰度和解决1px的问题又推出了高清适配方案,主要是把像素比考虑进去,结合第二种第三种方案来实现。方法是先用设备宽度与pdr相乘然后取到与设计稿的比例,动态设置html的font-size,最后再根据pdr的值动态设置scale来实现缩放。
备注:1px问题指的是在使用rem后,会出现像素值为小数的情况,小数位可能会被系统直接忽略掉,出现宽窄不同的现象。
附普通适配方案(代码摘自网络):
1 <script type="text/javascript"> 2 new function (){ 3 var _self = this; 4 _self.width =1080;//设置UI提供的基准尺寸 5 _self.fontSize = 200;//默认字体大小,使用时除以此参数作为rem,建议取10或100容易计算。为保证谷歌良好适配,320/_self.width*_self.fontSize>12 6 _self.widthProportion = function(){ 7 var p = (document.body&& 8 document.body.clientWidth || 9 document.getElementsByTagName("html")[0].offsetWidth)/_self.width; 10 11 return p>0.71?0.71:(p<0.3?0.3:p); //设置安全尺寸最宽768px,最小320px 12 }; 13 console.log(_self.widthProportion()); 14 _self.changePage = function(){ 15 document.getElementsByTagName("html")[0].setAttribute("style","font-size:"+_self.widthProportion()*_self.fontSize+"px !important"); 16 } 17 _self.changePage(); 18 window.addEventListener("resize",function(){_self.changePage();},false); 19 }; 20 21 </script>
高清适配方案(代码摘自网络):
1 <script> 2 (function(doc, win, designSize) { //designSize为设计稿的尺寸(宽) 3 var docEl = document.documentElement, 4 devWidth = docEl.clientWidth > 1080 ? 1080 : docEl.clientWidth, 5 dpr = devicePixelRatio || 1, 6 scale = 1 / dpr, 7 width = dpr * devWidth, 8 resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'onresize', //判断横屏和窗口重置 9 recalc = function() { 10 var clientWidth = docEl.clientWidth; 11 if (!clientWidth) return; 12 document.querySelector('meta[name="viewport"]') .setAttribute('content','width=' + width + ', 13 initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no'); 14 docEl.style.fontSize = devWidth / (designSize / 100) * dpr + 'px'; 15 }; 16 if (!doc.addEventListener) return; 17 win.addEventListener(resizeEvt, recalc, false); 18 doc.addEventListener('DOMContentLoaded', recalc, false); 19 })(document, window, 750); 20 </script>
参考文章:
https://segmentfault.com/a/1190000008767416
http://www.aliued.com/?p=3166
https://www.jianshu.com/p/07669cb3e7c5