移动端的开发基本很少直接使用px作为单位了,目前最常用的是rem。不过在这之前其实还有个em单位,和rem长得非常的像,那么它们有什么区别呢?又有什么不一样的适用场景呢?

注意:无论使用em,还是rem,客户端最终解析的值依旧是px!

em:相对父级元素字体大小的倍数

从title的解释就可以看出,em的基准是其父级元素,不过这个父级元素要求是设置有font-size值的,如下面的例子:

<div class="father" style="font-size:20px;">
    <div class="son"  style="font-size:2em;"></div>
</div>

那么son的字体大小就是2 * 20px = 40px,此时,如果father的字体大小变化了,那么son的也会跟着变化。假如没有父元素,则基准就是body(由于默认浏览器默认字体为16px,所以默认情况1em=16px)。

rem:相对 html 根元素字体大小的倍数

跟上面解释body基准时的差不多,默认情况下1rem=16px。此时,只要根元素字体大小不变,那么相对于它的rem就不会变。
对于移动端的各种机型来讲,由于不同的机型屏幕尺寸、分辨率都不一样,不太可能使用相同的根元素字体大小作为基准,所以所谓rem布局,就是通过js动态计算出不同机型的根元素字体大小值,来对页面进行等比例的缩放,达到适配大部分机型的效果。
那么具体如何去设定这个基准呢?
假设把手机屏幕宽度均分成10等份(因为rem布局就是针对宽度去做设定的),规定其中的一份作为根元素的font-size值,那么根元素font-size值就可由下述公式获得:

document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';

在这个基准下,那么1rem的值也随之得到了:

1rem = document.documentElementstyle..fontSize = document.documentElement.clientWidth / 10 + 'px';

那么,不同屏幕的机型由于屏幕宽度不同,也就得到了在"屏幕宽度均分成10等份"这个标准下的rem相对值。比较完整的计算方式如下:

// set 1rem = viewWidth / 10
function setRemUnit () {
  var rem = docEl.clientWidth / 10
  docEl.style.fontSize = rem + 'px'
}

setRemUnit()

// reset rem unit on page resize
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function (e) {
  if (e.persisted) {
    setRemUnit()
  }
})
注意:这里的标准 "10"可以是任一值,只要跟下面转换公式中用到的标准值保持一致即可,这里只是为了计算方便才这么设定。

这样,rem的基础生态就搭建好了。那么如何基于这套标准应用到开发中去呢?

在继续之前,先来了解下"像素"这个知识点,因为接下来都会用到它的概念。
像素分为两种:设备像素和CSS像素
1、设备像素(device independent pixels): 设备屏幕的物理像素,任何设备的物理像素的数量都是固定的
2、CSS像素(CSS pixels): 又称为逻辑像素,是为web开发者创造的,在CSS和javascript中使用的一个抽象的层
在pc端,css像素和物理像素是1:1的关系;而在移动端,由于类似retina的各种高清屏的出现,css像素和物理像素的关系一般是1:2或者1:3,即1个css像素容纳2到3个物理像素,实现高清的效果。

一般移动端页面的开发流程是:设计人员以某个机型作为标准,设计好UI。前端开发针对这个机型的UI做开发,然后其它机型相对的去等比例缩放。
这里以iphone6作为标准(因为实际开发中基本也是用它做设计),它的物理像素为750x1334,css像素为375*667,假设UI上图片a的宽度为140,那么如何把它转换成以rem为单位的值呢?
现在屏幕宽度是已知的10rem,要求UI上宽140的rem值,假设为X,由下图可以很容易的得到比例关系:

屏幕宽度/UI宽度 = x/140 = 10rem / 750
=》
x = 140 / 750 * 10 rem

image
一般可以在sass中通过封装预处理函数进行这个转换过程:

$UI_WIDTH: 750;

@function px2rem($px) {
  @return ${ $px / $UI_WIDTH * 10 }rem;
//=>or @return ${ $px / 75 }rem;
}

img{
  width: px2rem(140);
}

这就是"rem布局"原理的整个实现过程!

而随着社区各种工具的完善,现在也无需手动去使用如px2rem的这种预处理函数去转换,比较流行的做法是使用postcss的postcss-px2rem插件去自动处理,开发时仍然按照px的方式去编程,postcss配置例:

postcss: function() {
  return [px2rem({remUnit: 75})]; //设置基准值,75是以iphone6的标准
}

这里的remUnit设置是有一定规则的,比如屏幕宽度等分成10份,当UI以iphone6(即物理像素宽度750)设计时,remUnit=75;当UI以iphone5(即物理像素宽度640)设计时,remUnit=64。可以看出它中遵循如下公式:

remUnit = 物理像素宽度 / 设定的屏幕宽度等分值;

至于具体的js等分逻辑封装可以参看手淘的flexible

em 还是 rem ?

那么在实际开发中,究竟适用em还是rem呢?记住如下原则即可:

  1. 如果属性值根据元素的font-size获得,则使用em,如padding、margin、line-height等
  2. 其他情况都使用rem
本文收录在个人的Github上https://github.com/kekobin/bl... ,觉得有帮助的,欢迎start哈。支持原创,未经本人同意,请勿转载!

前端斌少
4 声望0 粉丝