清姿
IN A GOOD WAY

移动端适配方案,说多也很多。可以使用百分比布局,但百分比与em都是基于父元素进行计算的,在实际应用中不是很方便。使用rem不仅可以设置字体大小,块大小也可以设置。而且可以良好的适配各种终端,所以这方案很受欢迎。

rem定义及浏览器支持情况

rem(font size of the root element)是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。看到rem一定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很相似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。可以先看看rem的浏览器支持情况:

  1. 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.
  2. Reportedly does not work on Android 4.3 browser for Samsung Note II or the Samsung Galaxy Tab 2 on Android 4.2.
  3. Borders sized in "rem" disappear when the page is zoomed out in Chrome.
  4. 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).
  5. 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>

图图:

 

参考:

http://www.alloyteam.com/2016/03/mobile-web-adaptation-tool-rem/?utm_source=tuicool&utm_medium=referral#prettyPhoto

 

posted on 2016-06-21 18:58  清姿  阅读(18234)  评论(0编辑  收藏  举报