rem布局是现在比较流行的移动端布局,掌握了这种布局方式后,可以很轻易的实现布局自适应手机屏幕。目前淘宝首页就是采用的这种布局方式。
我曾经上网查过很多资料,看过很多解释原理的和使用方法的,可是还是一脸懵逼,可能我是一枚女程序员,脑子转不过来,必须要弄得很清楚透彻才能想明白这个布局的原理。后来我自己在纸上琢磨,用数学公式成功把自己弄明白了。希望也能帮到大家。就像一道数学题一样,见下题:
首先,假设UI给了一张 a(px)的设计稿,手机屏幕宽度为b(px),设置html根元素的字体大小为c(px)。如果现在设计稿上面有个d(px)的元素,那么这个元素在这个手机屏幕上占多少(px)?那么应该设置多少rem呢?
解:设这个元素在手机屏幕上占e(px)
(1)那么元素在设计稿上面的比例和元素在手机屏幕上的比列保持一致,得:d/a=e/b => e=db/a (px)
(2)由于手机上html根元素字体为c(px),所以:1(rem)=c(px)。(这是基础知识,不知道的可以自行百度w3c标准)
(3)那么e(px)=e/c(rem)
(4)把“(1)"得到的e带入”(3)“得:e(px)=db/ac(rem)
(5)这时候,令c=b/a,则e(px)=db/ac(rem)=d(rem)
此时便可得出:当html的font-size为 b/a (px)的时候,设计稿上的元素为d(px),则在css里面设置为d(rem)
(6)但是由于b/a很可能是小数或者很小的整数,而浏览器页面可设置的最小字体大小为12px,所以可以设置html的font-size为(b/a)*10或者(b/a)*100更合理准确。这里以(b/a)*100为例,如果html的font-size为(b/a)*100,即:c=(b/a)*100,重新带入”(5)“计算得:e(px)=db/ac(rem)=d/100(rem)。
(7)这样就得出结论了:当html字体元素设置为(b/a)*100px时,则在移动端设备上,根据设计稿可以把设计稿上的元素长度除以100便为需要设置的rem。
举例:设计稿为200px,手机屏幕宽为400px,则设置html字体元素为(400/200)*100像素,即:200(px),若设计稿上某个元素宽为96px,则在css里面可以设置为0.96rem,实现了同比缩放或扩大
重点:在搞明白了这个原理后,主要就是怎么设置html的字体大小了。并且是动态设置,(b/a)*100,设计稿固定,则a为固定已知的,主要就是怎么在不同设备上动态获取b(手机屏宽),这里有个js,可以动态计算并设置html的字体,在进入页面的时候加载该js即可(此外如果不用这个js设置,也可以用媒体查询方式设置不用屏宽情况下html的font-size):
js设置方式代码(以设计稿宽为375px举例):
//designWidth:设计稿的实际宽度值,需要根据实际设置
(function(designWidth) {
var doc = document,
win = window,
docEl = doc.documentElement,
remStyle = document.createElement("style"),
tid;
function refreshRem() {
var width = docEl.getBoundingClientRect().width;
var rem = width * 100 / designWidth;
remStyle.innerHTML = 'html{font-size:' + rem + 'px;}';
}
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(remStyle);
} else {
var wrap = doc.createElement("div");
wrap.appendChild(remStyle);
doc.write(wrap.innerHTML);
wrap = null;
}
//要等 wiewport 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
refreshRem();
win.addEventListener("resize", function() {
clearTimeout(tid); //防止执行两次
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener("pageshow", function(e) {
if (e.persisted) { // 浏览器后退的时候重新计算
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
if (doc.readyState === "complete") {
doc.body.style.fontSize = "16px";
} else {
doc.addEventListener("DOMContentLoaded", function(e) {
doc.body.style.fontSize = "16px";
}, false);
}
})(375);