现在移动设备屏幕尺寸繁多,比如iPhone SE到iPhone Plus,安卓机品类更多。为了用户体验,不同屏幕我们都得去适配。在移动端页面制作,我们一般会把单位px换成rem,然后通过媒体查询,js计算等方式,修改html的字号大小,从而整体修改页面大小,打到适配效果。大屏幕就让文字稍微大点,小屏幕下文字就稍微小点。整体比例上看起来是一致的。
对于rem,在W3C官网上是这样描述的:“font size of the root element”。一个网页中,rem就只有一个固定的参考值。不像em不固定。
前面提到用媒体查询方式做适配。这样就要写很多种情况判断。根据屏幕宽度,在一定宽度范围内,设置html的font-size为多少。维护起来比较不方便。
另一种就是通过js计算屏幕宽度,来设置html的font-size大小。
在我实际工作项目中,也是采用的这种方式。在构建页面的时候,在head里面会加入一段rem.js代码。这段代码就是用来根据屏幕页面宽度动态计算设置root element的font-size。
代码如下:
<script>
(function(win) {
var doc = win.document,
html = doc.documentElement,
option = html.getAttribute("data-use-rem");
if (option === null) { return }
var baseWidth = parseInt(option).toString() === "NaN" ? 640 : parseInt(option);
var grids = baseWidth / 100;
var clientWidth = html.clientWidth || 320;
html.style.fontSize = clientWidth / grids + "px";
var testDom = document.createElement("div");
var testDomWidth = 0;
var adjustRatio = 0;
testDom.style.cssText = "height:0;width:1rem;";
doc.body.appendChild(testDom);
var calcTestDom = function () {
testDomWidth = testDom.offsetWidth;
if (testDomWidth !== Math.round(clientWidth / grids)) {
adjustRatio = clientWidth / grids / testDomWidth;
var reCalcRem = clientWidth * adjustRatio / grids;
html.style.fontSize = reCalcRem + "px"
} else {
doc.body.removeChild(testDom)
}
};
setTimeout(calcTestDom, 20);
var reCalc = function () {
var newCW = html.clientWidth;
if (newCW === clientWidth) { return }
clientWidth = newCW;
html.style.fontSize = newCW * (adjustRatio ? adjustRatio : 1) / grids + "px"
};
if (!doc.addEventListener) { return }
var resizeEvt = "orientationchange" in win ? "orientationchange" : "resize";
win.addEventListener(resizeEvt, reCalc, false);
doc.addEventListener("DOMContentLoaded", reCalc, false)
})(window);
</script>
在代码前几行有这样一段option = html.getAttribute("data-use-rem");
。这是获取页面上配置的默认UI设计宽度尺寸的。我们用的是750px的。那么在html页面上,就会在html标签上添加 data-user-rem="750"
这样一个属性。
e.g.
<!DOCTYPE html>
<html lang="zh-CN" data-use-rem="750">
我们是以100倍来换算px/rem的。在sass里编写了px2rem的函数。
e.g.
//px转rem
//width:rem(100) or width:rem(100px)
@function rem($values) {
@if length($values) == 1 {
@return px-to-rem(nth($values,1))
}
@else if length($values) == 2 {
@return px-to-rem(nth($values,1)) px-to-rem(nth($values,2));
}
@else if length($values) == 3 {
@return px-to-rem(nth($values,1)) px-to-rem(nth($values,2)) px-to-rem(nth($values,3));
}
@else if length($values) == 4 {
@return px-to-rem(nth($values,1)) px-to-rem(nth($values,2)) px-to-rem(nth($values,3)) px-to-rem(nth($values,4));
}
}
@function rm-unit($num) {
@return $num / ($num * 0 + 1);
}
@function px-to-rem($values,$browser-base-num:100) {
@return (rm-unit($values)/rm-unit($browser-base-num))*1rem;
}
在UI图上,我们量出的尺寸大小是多少就用多少rem,比如UI上宽度为80px,写scss的时候,就写成width: rem(80)
; UI上的文字大小为32px,scss就写font-size: rem(32)
。
这样做的目的是减少我们人为的去计算转换px2rem。
另外,rem这个单位不是万能的,有的时候我们该用px的还是用px,移动端适配其实用px,%在大多数情况下也是完全OK的。还有vw,vh等,灵活运用就好。