之前在做一个移动端的项目(rem)的时候,发生过一个特别神奇的事情,大概就是在大多数机型都是正常的,但是个别机型,或宽度超出窗口的宽度,产生横向滚动条。
付上初版rem规则代码
(function (doc, win) {
var pxOneRem = 0;
// 我们的规则是 窗口100%宽度的rem = 10rem
// 我们在写css的时候,也要按照这个标准来写
/*
css 公式,假如设计稿的宽度是750px,那么w变量的元素,实际的rem值是
这是一个简单换算公式,实际项目中可以使用px2rem-loader配置
function c (w) {
const width100 = 750
const remClient = 10;
return Number((10*(w/750)).toFixed(3))
}
*/
var remClient = 10;
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
// 计算html的font-size
recalc = function () {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
// 这里定一个页面的最大宽度
clientWidth = clientWidth > 900 ? 900 : clientWidth;
pxOneRem = clientWidth / remClient;
docEl.style.fontSize = pxOneRem + 'px';
};
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
//当dom加载完成时,或者 屏幕垂直、水平方向有改变进行html的根元素计算
})(document, window);
这样看来是没有什么问题的,但是在某些机型(如华为、小米某些安卓机型),就会发生出现一些滚动条(宽度超出)的现象,调试发现就一些地方使用10rem的宽度(认为是100%)造成了宽度超出。
我们这里假设我们的pxOneRem为32(px),我们现在要计算10rem的元素究竟真实的宽度为多少。那么有些小伙伴肯定会认为10 x 32 = 320,其实准确的计算方式并不是这样,实际上rem真实的计算方式是:rem值*根目录上的font-size数值的一个字的真实宽度= 实际像素(10 x dom(style:font-size:32px).width)
发现使用上述两种计算方式出来的值是误差的,说明font-size=16px的一个字,他的真实宽度并不一定就是16px,所以我们需要对rem的pxOneRem 进行纠错。
(function (doc, win) {
var pxOneRem = 0;
var remClient = 10;
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
clientWidth = clientWidth > 900 ? 900 : clientWidth;
pxOneRem = clientWidth / remClient;
docEl.style.fontSize = pxOneRem + 'px';
// 纠错函数
function adapt(){
var d = window.document.createElement('div');
d.style.width = '1rem';
d.style.display = "none";
var head = window.document.getElementsByTagName('head')[0];
head.appendChild(d);
var defaultFontSize = parseFloat(window.getComputedStyle(d, null).getPropertyValue('width'));
return defaultFontSize
}
pxOneRem = pxOneRem * pxOneRem / adapt();
docEl.style.fontSize = pxOneRem + 'px'
};
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
纠错逻辑是往dom里插入一个宽度为rem为1rem元素,计算出他的真实宽度,与pxOneRem做一个等比例计算。举例,理想中我们计算的出来的1rem的像素为 pxOneRem,而实际表现的值却为adapt(),那么纠错后的pxOneRem, 我们假设为x,那么 pxOneRem / x = adapt() / pxOneRem。
可能理解起来不直观,再用大白话描述一下这个公式,假设我们我们现在有一个屏幕为320px宽度,pxOneRem初步计算出来为32px,实际adapt计算出来的1rem的元素宽度却为36px,说明我们premx(32)大了,我们需要缩小这个premx以使得让1rem的元素宽度adapt算出来等于32px。所以 32/x = 36/32 => pxOneRem / x = adapt() / pxOneRem。