移动端适配方案,说多也很多。可以使用百分比布局,但百分比与em都是基于父元素进行计算的,在实际应用中不是很方便。使用rem不仅可以设置字体大小,块大小也可以设置。而且可以良好的适配各种终端,所以这方案很受欢迎。
rem定义及浏览器支持情况
rem(font size of the root element)是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。看到rem一定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很相似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。可以先看看rem的浏览器支持情况:
- Chrome 31-34 & Chrome-based Android versions (like 4.4) have a font size bug that occurs when the root element has a percentage-based size.
- Reportedly does not work on Android 4.3 browser for Samsung Note II or the Samsung Galaxy Tab 2 on Android 4.2.
- Borders sized in "rem" disappear when the page is zoomed out in Chrome.
- IE 9, 10 and 11 do not support rem units when used in the "line-height" property when used on :before and :after pseudo elements (https://connect.microsoft.com/IE/feedback/details/776744).
- Causes content display and scrolling issues on iPhone 4 which typically has Safari 5.1.
可以看到移动端基本支持:
ios:6.1系统以上支持;
android:2.1系统以上都支持;
桌面端IE支持情况不乐观。
用法:
现代浏览器,IE9+,FireFox,Safari,Chrome,Opera,默认字体是16px,设置下根元素的字体大小为16px:
html { font-size:16px; }
,然后,如果希望某段文字的字体大小是12px,需要设置:
p { font-size: 0.75rem; //12÷16=0.75(rem) }
块大小的设置是类似的,所以整个布局的关键就是设置根元素的字体大小了。设置好根元素字体大小值,布局就可以做到自适应了。
块大小的设置,来个例子:
设置根元素字体大小为37.5px,在iphone6里面需要一个宽100px的块,就是这样了:
<!DOCTYPE html> <html> <meta charset="utf-8"></meta> <head> <title>vertical-align</title> <style type="text/css"> html{ font-size:37.5px; } #contentBox{ width:2.667rem; height:2.667rem; background:pink; } </style> </head> <body> <div id="contentBox"> </div> </body> </html>
如果在iphone5下想得到一个100px的块,需要设置基准值(即根元素字号)为32px。
下面专门谈谈rem的基准值设置。
rem基准值设置
想要rem适配不同尺寸的设备,就需要针对不同设备设置合适的基准值,如上例所示。
问题来了,基准值设置成多少合适?
一般拿到的设计稿是375px(2倍稿)*2的,也就是iphone6的大小。那么对于iphone6来说,基准值可以设置为37.5px。即设备宽度/10。这里做了一个除以10的计算,是因为不希望font-size值太大。这样使用rem时值也不会太大了。
如果是iphone5,基准值就是32px。
问题又来了,如何根据设备尺寸来设置基准值?
有两个方法,通过css media query 和js添加基准值:
css media query:
@media (min-device-width : 375px) and (max-device-width : 667px) and (-webkit-min-device-pixel-ratio : 2){ html{font-size: 37.5px;} }
用media query来实现难覆盖到所有设备:
html { font-size : 20px; } @media only screen and (min-width: 401px){ html { font-size: 25px !important; } } @media only screen and (min-width: 428px){ html { font-size: 26.75px !important; } } @media only screen and (min-width: 481px){ html { font-size: 30px !important; } } @media only screen and (min-width: 569px){ html { font-size: 35px !important; } } @media only screen and (min-width: 641px){ html { font-size: 40px !important; } }
而通过js来设置,可以实现覆盖所有设备:
js来设置:
document.getElementsByTagName('html')[0].style.fontSize = window.innerWidth / 10 + 'px';
关于方案的利弊,其实上面的例子里面可以看出,rem为整数的时候,基准值为32px,36px这样的整数,换成px也是整数。但rem带有小数,比如1.75rem,在32px的基准只下计算得56px。那再看看其他机型的换算值:
代表机型 | 浏览器宽 | 对应尺寸 |
---|---|---|
iPhone 4/4s/5/5s | 320px | 56px |
Samsung Note 3, Nexus 5… | 360px | 63px |
iPhone 6 | 375px | 65.625px |
Google Nexus 6 | 412px | 72.1px |
iPhone 6 Plus | 414px | 72.45px |
可以看出,有些机型里面是有小数像素值的。小数像素可能会带来一定的误差,设计的同事像素眼很容易觉察到的。
在可以接受的情况下允许这些误差存在。在安卓机子上较多出现这类情况。
下面可以具体看下小数像素在浏览器里面的显示情况:
设置两组块,第一组是1.75rem*1.75rem的,第二组是1.85rem*1.85rem的,具体代码如下:
.block{ display:inline-block; width:1.75rem; height:1.75rem; background:rgba(0,0,255, .5); } .block:nth-of-type(2n){ background:rgba(255,0,0, .5); } .group2 .block{ widrh:1.85rem; height:1.85rem; }
效果图是
看下第一组块,在iPhone6下,每个块的尺寸应该是:1.75*37.5=65.625px;
但实际情况:
是的,浏览器会显示为65px或66px,而且没有规律的来显示。
这看起来有点不可思议,按道理来说,浏览器似乎应该全部舍弃小数65px,或者保留到66px,可事实却不是这样的。
到这里,可以假设:浏览器所做的渲染处理只是作用在元素的渲染尺寸上,但他们的真实尺寸仍是原始尺寸大小。
举个实际的例子来说,就是一个元素的尺寸是0.625px,他的渲染尺寸是1px,剩下的0.375px由临近元素填充;同理,如果一个元素是0.375px,其渲染尺寸是0px,但是会占有临近元素0.375px的空间。
然后带着这个假设分析下上面的例子:
第一个块的宽度为 65.625px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.375px 由第二个块补上;
第二个块向左补进 0.375px,相当于减少了 0.375px,余下 65.25px,根据四舍五入的原则其最终渲染尺寸为 65px,多出的 0.25px 会占用第三个色的空间;
第三个块被占用了 0.25px,相当于增加了 0.25px,等于 65.875px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.125px 由第四个块补上;
第四个块向左补进 0.125px,相当于减少了 0.125px,余下 65.5px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.5px 由第五个块补上;
第五个块向左补进 0.5px,相当于减少了 0.5px,余下 65.125px,根据四舍五入的原则其最终渲染尺寸为 65px,多出 0.125px;
这与浏览器的输出结果是一致的,印证了猜想。
更具体的浏览器处理可以看http://trac.webkit.org/wiki/LayoutUnit
其他适配方案
也可以采用固定布局:
1.在viewport meta标签上设置width=320,页面的各个元素也采用px作为单位。通过用JS动态修改标签的initial-scale使得页面等比缩放,从而刚好占满整个屏幕。
<meta name="viewport" content="width=320,user-scalable=no">
2.rem也可以使用自己设置viewport和content的方法来适配,以方便计算和设置值:
例如:
meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no');
其中dpr通过window.devicePixelRatio获取,iphone6的值是2.
对于2倍稿,可以直接设置基准值为2倍,这样就不用设计稿的值除以2了。
iphone6适配的设计稿750px,基准值设置为75px就可以了。
修改了缩放倍数之后,1px边线的问题也同时解决了。
代码:
<!DOCTYPE html> <html> <meta charset="utf-8"></meta> <meta name="viewport" content="" id="viewMeta"> <head> <title>vertical-align</title> <style type="text/css"> html{ font-size:75px; } #contentBox{ width:2.667rem; height:2.667rem; background:pink; border:1px solid #000; } </style> </head> <body> <div id="contentBox"> </div> </body> <script type="text/javascript"> var meta = document.getElementById('viewMeta'); var dpr = window.devicePixelRatio; meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no'); </script> </html>
图图:
参考: