基于 rem 的前端布局方案
2020-04-29 · 635 chars · 4 min read
本文很简单,分享一下我们目前使用的 rem 布局方案,大体的思路和之前社区里的其他方案基本一致,但是在实际使用中发现不少问题,逐渐演变成了今天的模样。
目前这套方案大体上是比较稳定的,可能日后随着设备的更新、迭代、升级,vw 等新方案会越来越普及,布局也就不会像现在这么麻烦了。
Note
演变过程中的问题大多比较琐碎和细节,受迫于整体开发进度比较紧张,部分兼容性问题没有记录下来,没有查清楚原因...
代码#
;(function (doc, win) {
var docEl = doc.documentElement
var resizeEvt = 'orientationchange' in win ? 'orientationchange' : 'resize'
/**
* 不管 fontsize 是多少,直接通过 clientWidth 对比
*
* 直接对比 fontsize 在 android webview 79+ 有问题
* 问题表现是:
* 有时设置 html font-size 16px,获取到是 20px,但是 rem 依然根据 16px 计算;
* 一加 7t 上更加奇怪,具体表现待查;
*/
var getClientWidthWithRem = function () {
var $div = doc.createElement('div')
$div.style.width = '3.75rem'
$div.style.visibility = 'hidden'
doc.head.appendChild($div)
var width = parseFloat(win.getComputedStyle($div).width)
doc.head.removeChild($div)
return width
}
var recalc = function (event) {
var clientWidth = docEl.clientWidth
/**
* 设备宽度大于 640px,fontSize 统一取上限值
*/
if (clientWidth >= 640) {
docEl.style.fontSize = (640 / 375) * 100 + 'px'
return
}
/**
* 传统 rem 方案
*/
var fontSize = (clientWidth / 375) * 100
docEl.style.fontSize = fontSize + 'px'
/**
* 再次校验,处理用户调整了系统字体大小的情况
*/
var currentClientWidth = getClientWidthWithRem()
if (Math.abs(currentClientWidth - clientWidth) > 1) {
docEl.style.fontSize = fontSize * (clientWidth / currentClientWidth) + 'px'
}
}
recalc()
if (!doc.addEventListener) {
return
}
win.addEventListener(resizeEvt, recalc, false)
doc.addEventListener('DOMContentLoaded', recalc, false)
})(document, window)
使用前提#
- 我们团队的视觉规范是宽 375,所以代码全部是按照 375 换算的,这是唯一前提。如果和你们的视觉规范不一致,调整计算规则即可
- 我们给 H5 限制了最大宽度 640,一定程度上保证了页面在 PC 浏览器上的体验,这里大家自行酌情调整
使用方式#
- 将代码压缩后插入
<head>(可以使用 terser 压缩),不建议外链,关键渲染路径优化 - 而后,所有尺寸除以 100,加单位 rem 即可。例如一个图片在视觉稿上宽 200,代码里写
2rem即可 - 一些如 1px 边框的问题,直接 transform 缩放即可
- 字体看情况处理,用 rem 和 px 都可以,主要还是看规范


