一、核心概述
我们知道rem是弹性布局的一种实现方式,它的本质是基于屏幕宽度的等比缩放,而rem的大小是根据html节点的font-size的相对值决定的,比如某款手机的屏幕宽度为468px,因此1rem === 46.8px。
核心:flexible.js可以计算出1rem 等于多少px(1rem = 屏幕宽度的1/10)
var doc = document.documentElement // 返回文档的root元素,即html
// docEl.clientWidth 计算视口宽度
var rem = doc.clientWidth / 10 // 计算rem
// 设置字体大小
doc.style.fontSize = rem + 'px'
二、计算rem的作用
抛出问题:
移动端页面需要适配两款手机屏幕,一个手机的屏幕宽度是375px,一个是468px,设计稿给我们的宽度是375px,那我们按照设计稿进行开发,在375px的手机上刚好完美匹配,但是却会发现在468px的手机上留有一定像素的空白。
解决办法:
现在我们把设计稿分成10等份,设计稿 A = W/10,我们把设备可视区域也就是我们的各种移动端设备的这个画布也分成10份,并赋值给根元素的fontSize,我们都知道rem是根据根元素字体大小计算的,所以我们的1rem也就是设备可视区域/10,现在设计稿上有一块区域宽B,那它是不是等比放到设备可视区域的宽度为 B/A rem。
// 首先是一个立即执行函数,执行时传入的参数是window和document
;(function flexible(window, document) {
var doc = document.documentElement // 返回文档的root元素
var dpr = window.devicePixelRatio || 1 // 获取设备的dpr,即当前设置下物理像素与虚拟像素的比值
// adjust body font size 设置默认字体大小,默认的字体大小继承自body
function setBodyFontSize() {
if (document.body) {
document.body.style.fontSize = 12 * dpr + 'px'
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize()
// set 1rem = viewWidth / 10
function setRemUnit() {
var rem = doc.clientWidth / 10
doc.style.fontSize = rem + 'px'
}
setRemUnit()
// reset rem unit on page resize
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit()
}
})
// detect 0.5px supports 检测是否支持0.5像素,解决1px在高清屏多像素问题,需要css的配合。
if (dpr >= 2) {
var fakeBody = document.createElement('body')
var testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
doc.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
doc.classList.add('hairlines')
}
doc.removeChild(fakeBody)
}
})(window, document)
这就是flexible.js的源码。
三、将设计稿分成10等份
Vant官网推荐的,postcss-pxtorem 是一款 PostCSS 插件,它可以将 px 单位转化为 rem 单位。
相关配置:(可以看看Vant官方文档)
// postcss.config.js
module.exports = {
plugins: {
'postcss-pxtorem': {
rootValue: 37.5,
propList: ['*'],
},
},
};