移动端REM布局适配
在公司大部分需求都是做移动端的H5页面,APP内嵌的H5 和 移动端WAP 站。这里总结一下我公司用的REM适配方法,再拓展一下其他方法。
rem 、 em 和 px
px
:绝对长度单位,与显示设备相关,对于屏幕显示,通常是一个设备像素(点)的显示。pc端的页面一般使用px作为css长度单位。em
:相对长度单位,这个单位表示元素的font-size
的计算值它是相对父元素而言的。值是一个倍数。浏览器的默认字体高都是 16px,未经调整的浏览器显示 1em = 16px。rem
: 相对长度单位,这个单位代表根元素(<html>
)的font-size
大小。值是一个倍数。
移动端页面显然不适用px
作为长度单位,手机的尺寸和分辨率不尽相同,页面难以做到统一。
en
单位有个问题,就是它是相对于其父级字体的倍数的,当出现有多重嵌套内容时,计算会变得很复杂,可能改变一个元素的字体大小,则子元素的尺寸都会跟着变化,需要重新计算。
rem
就不会有这个问题,因为它始终是基于根元素(<html>
)的。
所以,rem
是比较适合移动端的。
正在使用的方法
rem布局的本质是等比缩放,一般是基于宽度。最重要的是要给根元素(
<html>
)动态设置多少的font-size
合适。 一般是将设计稿的宽度等分为100份,然后将1份大小的px值设置为<html>
元素的font-size
大小。
比如,设计稿的宽度是750px,分成100份之后每份的大小为7.5px
,即设置<html>
元素的font-size
大小为7.5px
。在元素中1rem = 7.5px
。
如果设计稿中有一个宽20px的块,那在样式中就需要换算一下啦,width:2.667rem
。这里的转换看以来有点复杂,不过我们可以使用css预处理器或者gulp、webpack构建的时候进行转换。
1 rem = 7.5px;
x rem = 20px;
// 由比例关系可以得出:
x = 1 * 20 / 7.5
下面是我在公司一直在用的rem处理的代码,设置<html>font-size
的地方不是很明白其用意是什么,不过知道上面的转化规则,font-size
设置成多少,都能转化px2rem。
// 只适用于移动端,没有处理pc端的显示,在pc端页面会显示地很大。
(function(window, html) {
// 默认的设计稿宽度720px
var designWidth = 720;
function recalc() {
//var windowWidth = html.clientWidth < designWidth ? html.clientWidth : designWidth;
// 获取页面的宽度
var windowWidth = html.clientWidth;
// 我的理解是: 将页面等分成 designWidth 份
// 这样的话,设计稿中的1px 就等于 1rem,方便转换px和rem
// 后面又 *100 ,我觉得是确保计算出来的值是非小数,保证之后的计算精度。
// *100 之后,则样式中rem的值就需要相应的缩小100背
// 即:设计稿中的20px,在样式中就要写成0.2rem
var fontSize = windowWidth / designWidth * 100;
setFontSize(fontSize);
var completedFontSize = getFontSize();
// 如果实际 fontSize 与设置的 fontSize 不等,则根据比例,重新计算
// 存在浏览器自动放大font-size的问题
// 参考:https://www.cnblogs.com/keaizhouzhou/p/6702551.html
if (Math.abs(completedFontSize - fontSize) > 0.1) {
setFontSize(fontSize * fontSize / completedFontSize);
}
}
function setFontSize(fontSize) {
html.style.fontSize = fontSize + 'px';
}
function getFontSize() {
return parseFloat(window.getComputedStyle(html)['font-size']);
}
window.calcRem = function(width) {
designWidth = width;
recalc();
// 监听resize
window.addEventListener('resize', recalc);
}
}(window, document.documentElement));
在window上挂了一个calcRem
方法,如果设计稿的宽度是750px的,则执行calcRem(750)
。代码最好放在html中css加载之前执行。
上面的注释是我的理解,我觉得var fontSize = windowWidth / designWidth * 100;
这个算式是简化后得来的,具体怎么简化的我还真的想不明白。或许是考虑到了简化px到rem的转化计算问题。
不过,根据rem的定义,我们也很容易知道样式中的rem的值要怎么写。
px2rem 方法
css预处理器
我是用的是stylus
预处理器,可以定义一个方法:
// px转换rem的方法,这里的100是根据动态设置的html的font-size设置的
px2rem(pxValue) {
unit(pxValue / 100, rem);
}
// 样式中就可以使用方法,20和30都是设计稿的尺寸,写代码的时候就不用手动转换了
.sign-box {
padding: px2rem(20) px2rem(30);
}
gulp 构建时转换
webpack 构建时转换
postcss-px2rem
// vue.config.js
// remUnit是指1rem等于多少px的值,我这里1rem = 100px,则 remUnit为100
css: {
loaderOptions: {
postcss: {
plugins: [require('postcss-px2rem')({
remUnit: 100
})]
}
}
}
参考:
px2rem-loader
// vue.config.js
chainWebpack: config => {
config.optimization.splitChunks({
cacheGroups: {
vendors: {
name: 'chunk-vendors',
minChunks: 2,
chunks: 'initial'
}
}
});
config.module
.rule('stylus')
.oneOf('vue')
.use('px2rem-loader')
.loader('px2rem-loader')
.before('postcss-loader') // this makes it work.
.options({ remUnit: 100, remPrecision: 8 })
.end()
}
参考:
待学习
不懂的东西还特别多,文中有错误的地方麻烦指出。