对于页面适配,你应该使用px还是rem

746 阅读10分钟
css中的单位很多,%、px、em、rem,以及比较新的vw、vh等。每个单位都有特定的用途,比如当需要设置一个矩形的宽高比为16:9,并且随屏幕宽度自适应时,除了用%,其他单位是很难做到的。所以不存在说某个单位是错误的,某个单位是最好的这种说法。
那本文说的页面适配,指的是同样的布局,在不同大小的屏幕上怎么进行缩放、控制间距、宽高、字号等大小。
页面适配的方式有很多:
  • 使用px,结合Media Query进行阶梯式的适配;
  • 使用%,按百分比自适应布局;
  • 使用rem,结合html元素的font-size来根据屏幕宽度适配;
  • 使用vw、vh,直接根据视口宽高适配。


在这些大前提下,还需针对一些小的细节做微调。比如使用px的时候,可能在小屏幕中,要对某个容器进行transform: scale(.8),适当缩小处理。使用rem的时候,需要固定页面的左右间距为10px等。
所以对我来说,尽管网上曾对px、rem和em等单位的优缺点争论过很多,但我的观点可能是,具体情况具体分析。有同学可能要炸了,你这跟没说有啥区别?
对,我的意思跟开篇一样,单论某个单位的好坏是没意义的。我们最关注的是:什么场景中,使用什么单位最合适。
也不卖关子了,我就直接列一些自己觉得比较好的实践方式,这些都是根据自己多年的开发经验和大量的调研得到的结论:
  • 在视觉稿要求固定尺寸的元素上使用px。比如1px线,4px的圆角边框。
  • 在字号、(大多数)间距上使用rem。
  • 慎用em。


为什么我标题没提到%、vw、vh这几个呢?这几个都是按比例适配,只不过参考对象不一样。
%是参考父容器,vw和vh是参考视口。他们的使用场景是非常固定的,比如上文提到的16:9的容器,除了用%,还有更合适的方式吗?另外,1vw = 1%的视口宽度。所以就真正需要按视口大小适配的时候再用这个单位吧,使用场景相对固定。
接下来我会详细介绍一下这3个结论的由来。
为什么慎用em?
em会叠加计算。在这个机制下太容易犯错了,因为你不知道这段css指定的字号具体是多少。
  • [HTML]
    纯文本查看
    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    <font style="color:rgb(190, 190, 197)">// HTML
    <span>
    abc
    <span>def</span>
    abc
    </span>
    // CSS
    span {font-size: 1.5em;}</font>


先要搞清楚em的计算原理,它是根据当前元素的字号按比例计算的。
外层span的字号是16px(浏览器默认值),所以1.5em之后是24px。由于字号是继承的,导致内层span的字号继承过来是24px,再经过1.5em之后就成了36px。
所以,就算要用em的话,尽量不要用在继承属性(font-size)上,除非你真的清楚你在做什么!
比如你想根据字号自动调整字符间距,可以这么做:
  • .content {

  • font-size: 1rem;

  • letter-spacing: .03em;

  • }


但再仔细想一下,letter-spacing由.content的字号决定,而它又由html的字号决定。那为什么letter-spacing不直接用rem呢?
rem vs. px
px是我比较喜欢的一个单位,简单又直接。但理性驱使,还是要合理考虑使用场景。
px的性质决定了它只能用于固定尺寸。也就是说,如果视觉设计师规定,这个边框宽度必须是2px。那这种情况下就不需要讨论了。
除了固定尺寸用px,其他大部分情况都可以使用rem。
现在考虑一个实际的开发场景,一般来说都是先有视觉稿才能开发。两种情况:一、假设视觉稿按iPhone 6和iPhone 6+,及其他尺寸各出了一份,那你就按照Media Query去适配。二、设计师只给你一种机型的视觉稿,以iPhone 6为例,750x1334,2倍屏下转换后是375x667。
第一种情况也不讨论了,通过Media Query断点适配后,其实你处理的还是第二种情况。
那第二种的意思是,你要根据宽度为375px的稿子,扩展到适配任意宽度的屏幕。(页面高度跟业务有关,不用关心,宽度肯定是固定的)
接下来拿到视觉稿如下:

测量后主要参数如下:
  • 页面间距10px
  • 文字间距10px,字号16px
  • A高度100px
  • B高度50px,上间距30px


很快就能写出HTML结构和CSS。
  • <div class="box box-1">A. 第一段内容</div>

  • <div class="box box-2">B. 第二段内容</div>


  • [CSS]
    纯文本查看
    复制代码
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <font style="color:rgb(190, 190, 197)">body {
    padding: 10px;
    background: #f6f0ee;
    }
    .box {
    padding: 10px;
    font-size: 16px;
    color: #fff;
    box-sizing: border-box;
    }
    .box-1 {
    height: 100px;
    background: #1daedc;
    }
    .box-2 {
    margin-top: 30px;
    height: 50px;
    background: #ddbe97;
    }</font>


完美符合要求。
然后视觉开始提要求了,大屏上要把字体放大、间距放大。
这时候的一个选择是,问设计师是要适配哪种屏幕,字号是多少,间距是多少。技术上再通过Media Query微调。
  • @media(min-width: 414px) {

  • // 这里不写了,按视觉要求量化即可

  • }


另一个选择可以反过来做。首先按rem作为字号、容器高度、外间距的单位。那么代码可以改为:
  • [CSS]
    纯文本查看
    复制代码
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    <font style="color:rgb(190, 190, 197)">html {
    font-size: 16px;
    }
    .box {
    font-size: 1rem;
    }
    .box-1 {
    height: 6.25rem;
    }
    .box-2 {
    margin-top: 1.875rem;
    height: 3.125rem;
    }</font>


其他的样式规则不变,目前的结果和之前的是等价的。如果再加一点魔法,通过Media Query改变iPhone 6+的html字号,其他元素的属性就会自动变化。
  • [CSS]
    纯文本查看
    复制代码
    1
    2
    3
    4
    5
    <font style="color:rgb(190, 190, 197)">@media(min-width: 414px) {
    html {
    font-size: 17.664px;
    }
    }</font>


17.664 = 414 * 16 / 375。
由此可以得到html的font-size计算公式为:fontSize = deviceWidth * 16 / 375;
前提是你的html有这条meta属性:
  • <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no">


至于为何是16px,这个后面再介绍。所以rem有个明显的优点,它可以通过少量代码解决大部分问题
如果还存在某些细节不够满意,那再用Media Query微调。这种主观的“好看”、“不好看”,可能注定没法自动化解决吧。
关于rem兼容性。桌面端的话仅在IE9+支持。vw和vh一样。所以如果要考虑IE8的兼容性,那没别的选择只能用px吧。至于移动端,支持情况不错,可以在生产环境使用。
html的font-size该如何设置
由于(大部分)浏览器的默认字号为16px,所以一般来说把html的font-size归一化为16px是比较合适的实践方式。同时可以参考这篇文章。
为了大家以后参考方便,我列了一些常用的Media Query断点(以iPhone 6为基准)。
  • [CSS]
    纯文本查看
    复制代码
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <font style="color:rgb(190, 190, 197)">@media only screen and (min-width: 320px) {
    html {
    font-size: 13.65px;
    }
    }
    @media only screen and (min-width: 360px) {
    html {
    font-size: 15.36px;
    }
    }
    @media only screen and (min-width: 375px) {
    html {
    font-size: 16px;
    }
    }
    @media only screen and (min-width: 390px) {
    html {
    font-size: 16.64px;
    }
    }
    @media only screen and (min-width: 414px) {
    html {
    font-size: 17.664px;
    }
    }
    @media screen and (min-width: 640px) {
    html {
    font-size: 27.31px;
    }
    }</font>


大家可能还会看到一些文章中建议把html字号设成62.5%。
  • [CSS]
    纯文本查看
    复制代码
    1
    2
    3
    <font style="color:rgb(190, 190, 197)">html {
    font-size: 62.5%;
    }</font>


因为刚提到浏览器默认的字号为16px,因此换算成百分比就是62.5% = 1 / 16。
那为什么要用百分比呢?因为考虑到辅助功能和浏览器设置。对于部分用户,可能会在手机或浏览器的设置中增大手机字号,这意味着对方平时看字是很费力的,所以他才要放大。那把html的字号设置成百分比就很贴心了,会随着手机设置改变页面的字号。
在手机上设置默认字号是很常见的现象,所以如果是一个充满人道主义的排版,我觉得用百分比是非常高尚的。它不仅从视觉角度去考虑美,更加做到了“用户至上”这四个字。
好,回到现实环境。只有国外那些对Accessibility要求比较高的国家,才会真正去落实这些。但国内的话,老实说,更注重外观的美。从来没有哪家互联网公司的页面会去兼容Screen Reader,也很少做Keyboard Shortcut。
扯远了,就算你看到用62.5%的情况,有些间距也是不合理的,都做的不太好,特别是把文案做到图片上的,对字号根本不敏感。如果出发点不是为了用户的视觉接受能力,那就别用62.5%;如果想做,就把缩放考虑到位了,别做半吊子。
另外,针对本小节开头用16px的情况,这里再给大家提供一招(我调研了一下目前没人这么用,也是灵光一现才想到的)。
用Media Query的缺点是什么?它是分段函数,对于宽度在[320, 360)区间内的屏幕,会适用同一套方案。最完美的应该是线性函数,怎么做?很简单,用vw即可。
  • html {

  • font-size: 4.266667vw;

  • }


用1行代码代替之前6个冗长的Media Query,还不错吧。
如何提高rem的可读性
我们来谈最后一个话题。
当你知道html的font-size怎么设置后,肯定想问,难道我每次写代码时,还得做个除法,把rem的值计算出来吗?
我相信稍微“现代”一点的开发者,都会用到CSS预处理。基于这个工具,事情就很好办了,以LESS为例,两步操作如下:
  • [CSS]
    纯文本查看
    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <font style="color:rgb(190, 190, 197)">// 1\. 按iPhone 6的视觉稿,基准字号为16px,因此可以设置一个LESS变量。
    @px: 16rem;
    // 2\. 通过LESS内置的除法自动运算。比如用到16px的字号时,写成16/@px即可,最后会计算成1rem。
    .example {
    font-size: 16/@px;
    margin: 20/@px 0;
    padding: 20/@px 10/@px;
    }
    </font>

更多技术资讯可关注:gzitcast