移动Web开发之rem

rem(一个CSS单位)

定义:font size of the root element.

这个单位的定义和em类似,不同的是em是相对于父元素,而rem是相对于根元素。rem定义是根元素的font-size, 以rem为单位,其数值与px的关系,需相对于根元素的font-size计算,比如,设置根元素font-size=16px, 则表示1rem=16px。关于rem更多的解读,建议可以腾讯一团队的文章《web app变革之rem》。 根据这个特点,可以根据设备宽度动态设置根元素的font-size,使得以rem为单位的元素在不同终端上以相对一致的视觉效果呈现。 选取一个设备宽度作为基准,设置其根元素大小,其他设备根据此比例计算其根元素大小。比如使得iPhone6根元素font-size=16px。

设 备 设备宽度 根元素font-size/px 宽度/rem
iPhone5 320 js计算所得
iPhone6 375 16 23.4375
i6 Plus 414 js计算所得
- 360 js计算所得

根元素fontSize公式:width/fontSize = baseWidth/baseFontSize其中,baseWidth, baseFontSize是选为基准的设备宽度及其根元素大小,width, fontSize为所求设备的宽度及其根元素大小

动态设置根元素fontSize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 以下这段代码是用于根据移动端设备的屏幕分辨率计算出合适的根元素的大小
* 当设备宽度为375(iPhone6)时,根元素font-size=16px; 依次增大;
* 限制当为设备宽度大于768(iPad)之后,font-size不再继续增大
* scale 为meta viewport中的缩放大小
*/
(function (doc, win) {
var docEl = win.document.documentElement;
var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
/**
* ================================================
* 设置根元素font-size
* 当设备宽度为375(iPhone6)时,根元素font-size=16px;
× ================================================
*/
var refreshRem = function () {
var clientWidth = win.innerWidth
doc.documentElement.clientWidth
doc.body.clientWidth;

console.log(clientWidth)
if (!clientWidth) return;
var fz;
var width = clientWidth;
fz = 16 * width / 375;
docEl.style.fontSize = fz + 'px';
};

if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, refreshRem, false);
doc.addEventListener('DOMContentLoaded', refreshRem, false);
refreshRem();

})(document, window);

rem计算(px2rem)

对于需要使用rem来适配不同·屏幕的元素,使用rem来作为CSS单位,为了方便,可以借助sass写一个函数计算px转化为rem, 写样式时不必一直手动计算。sass函数的使用若不熟悉可看下这篇文章:如何编写自定义Sass 函数, 也可以使用sass的mixin来写,个人觉得用函数写更适合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
* 此处 $base-font-size 具体数值根据设计图尺寸而定
* flexible中设置的标准是【fontSize=16px, when 屏幕宽度=375】,因此,按此标准进行计算,
* 若设计图为iPhone6(375*667)的二倍稿,则$base-font-size=32px
*
*/
@function px2rem($px, $base-font-size: 32px) {
@if (unitless($px)) {
@warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
@return px2rem($px + 0px); // That may fail.
} @else if (unit($px) == rem) {
@return $px;
}
@return ($px / $base-font-size) * 1rem;
}

// 使用,eg:
font-size: px2rem(18px);

问题思考

我之前一直在想一个问题,选取哪个设备来做基准、屏幕宽度等分为多少比较合适,设计图给多大宽度的版本?被选取作为基准的设备,应当就是前端需要设计提供的设计图版本,这样可以避免一些尺寸上的纠缠,而等分为多少等分,除了考虑方便设计,是否需要考虑其他问题?对于根元素font-size没有手动设置的情况,1rem究竟等于多少?

了解到的一些事实:

  • 某些Android设备会丢掉 rem 小数部分(具体是哪些设备,搜到的文章中没有说),那么1rem对应的px少些,在这些安卓设备上显示误差就会较小,当然如果不存在会丢掉小数这个问题,这一说也就不必考虑了。
  • 未设置font-size情况下,1rem的大小具体看浏览器的实现,默认的根元素大小是font-size=16px
  • 目前一般会选取iPhone6作为基准,设计图便要iPhone6的二倍图
  • 当动态缩放视口为1/dpr, 计算所得的根元素fontSize也会跟着缩放,即若理想视口(scale=1), iPhone6根元素fontSize=16px; 若scale=0.5, iPhone6根元素fontSize=32px; 因此设置视口缩放应放于设置根元素fontSize之前。

注:文章转载自移动Web页面适配方案

评论