# rem
说rem之前先说一下em。这两个都是相对长度单位
em在 font-size
中使用时是相对于父元素的字体大小,在其他属性中使用是相对于自身的字体大小,如 width
。我们常用的段落首行缩进2个字体大小就是用的text-indent: 2em;
概括地说,在排版属性中 em 单位的意思是“父元素的字体大小”。而rem 单位的意思是“根元素(html)的字体大小,即(root em)。
# 1、长度计算逻辑
<html lang="en" style="font-size: 37.5px;">
<style>
.box {
width: 2rem;
}
</style>
比如上面的例子,box的实际宽度就是 37.5 * 2 = 75px
。以根元素的字体大小为相对值,节点本身的rem值为系数。
rem平时主要用在移动端的适配中,说两种实践的方式吧。
以下的例子都是建立在设计稿是375宽度的基础之上
# 2、自己计算rem值
为了方便我们自己计算rem的值。我们可以把rem设置为
var rem = document.documentElement.clientWidth / 375 * 100
这样子设置的最大好处就是非常方便计算。表达式里的375就是我们设计稿的宽度。比如设计稿里面元素的大小事20px。那么我们只需要除以100,设置为0.2rem即可。缺点就是需要我们手动计算一次。还有一个缺点就是根元素的字体大小会设置的比较大。 以实际设备宽度为375px来看,根元素的字体大小就是100px,此时为了防止这个属性被其他元素继承到,导致出现很大的文字,需要适当的给body设置一个合适的font-size。
以设计稿宽度为375举例
设备宽度 | html rem值 | 设计稿尺寸 | 实际设置值 | 实际渲染尺寸 |
---|---|---|---|---|
320 | 85.333px | 50px | 0.5rem | 42.666px |
375 | 100px | 50px | 0.5rem | 50px |
390 | 104px | 50px | 0.5rem | 52px |
414 | 110.4px | 50px | 0.5rem | 55.2px |
由上面的表格可以看到,同样的设计稿尺寸50px。除以100之后 设置元素的实际代码尺寸为0.5rem。实际渲染的尺寸就可以随着屏幕的宽度变化都变化了。
提供一个设置rem的代码片段
(function (win, uiWidth) {
var docEl = win.document.documentElement;
var _rem = {
rem: 0
};
var timer = null;
function resize() {
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
var width = docEl.clientWidth;
var rem = (width / uiWidth) * 100;
docEl.style.fontSize = rem + 'px';
_rem.rem = rem;
//误差、兼容性处理
var actualSize = parseFloat(window.getComputedStyle(docEl)['font-size']);
if (actualSize !== rem && actualSize > 0 && Math.abs(actualSize - rem) > 1) {
var remScaled = (rem * rem) / actualSize;
docEl.style.fontSize = remScaled + 'px';
_rem.rem = remScaled;
}
}, 50);
}
resize();
//窗口更新动态改变font-size
win.addEventListener('resize', resize, false);
win.addEventListener(
'pageshow',
function (e) {
if (e.persisted) {
resize();
}
},
false
);
_rem.resize = resize;
_rem.rem2px = function (remVal) {
var pxVal = parseFloat(remVal) * this.rem;
if (typeof remVal === 'string' && remVal.match(/rem$/)) {
pxVal += 'px';
}
return pxVal;
};
_rem.px2rem = function (pxVal) {
var remVal = parseFloat(pxVal) / this.rem;
if (typeof pxVal === 'string' && pxVal.match(/px$/)) {
remVal += 'rem';
}
return remVal;
};
// 主要用于一些通过js设置样式的代码, 暴露一个全局的对象
win._rem = _rem;
})(window, 375);
# 3、postcss-pxtorem
postcss-pxtorem (opens new window)。如果工程上有打包工具, 那么就可以使用这个postcss的插件了。
使用这个插件的好处就是不用自己计算和书写rem了,统一在编译的时候搞定。举个例子, 比如375宽度的设计稿,元素设计稿尺寸是多少,就写多少, 编译之后会自动转换px单位到rem单位。
如果是webpack之类的工具, 提供一个插件配置做参考
postcss.config.js
module.exports = {
plugins: {
'postcss-pxtorem': {
rootValue: 37.5,
unitPrecision: 3,
minPixelValue: 2,
propList: ['*']
}
}
};
如果设计稿是375的宽度,可以设置rootValue为37.5,于此 同时html元素的font-size设置,也不能采用上面第二节的方式, rootValue 可以理解为设计稿尺寸下根元素的字体大小。而是应该采用下面的方式
html.style.fontSize = html.clientWidth / 10 + 'px'
设计稿尺寸、pxtorem插件配置、根元素字体大小设置三者需要对应上。满足下面的逻辑
pxtorem.rootValue = 设计稿尺寸 / 10
根元素字体大小 = html.clientWidth / 10
这个10 采用的是一个经验值, 当时设置成其他的系数也是可以的, 只不过保持一致即可。
如果不想让px转换为rem。直接把px写成Px或者PX这种大写的即可。
提供一段设置rem的代码片段
!(function (win) {
var doc = window.document;
var html = doc.documentElement;
var ratio = win.devicePixelRatio || 1;
function onload() {
if (doc.body) {
doc.body.style.fontSize = 12 * ratio + 'px';
} else {
doc.addEventListener('DOMContentLoaded', onload);
}
}
function resize() {
const val = html.clientWidth / 10;
html.style.fontSize = val + 'px';
}
onload();
resize();
win.addEventListener('resize', resize);
win.addEventListener('pageshow', function (e) {
// 如果网页来自缓存
e.persisted && onload();
});
})(window);
← box-shadow 文本处理 →