移动端用 rem 是为实现跨设备等比缩放,其核心是通过动态设置 html font-size(公式:window.innerwidth / designwidth × basesize),确保 1rem 恒等于根字体大小,从而避免嵌套缩放失真、百分比失效等问题,且需配合 viewport meta 标签与 resize 监听。

移动端用 rem 不是为了“高大上”,而是因为不这么干,UI 在 iPhone 15 Pro 和 Redmi Note 13 上大概率会一个撑满、一个缩成小点——rem 是目前最可控、副作用最少的等比缩放方案。
rem 的缩放逻辑只依赖 html 的 font-size
这是它和 em、% 的本质区别:不管嵌套多深、父元素字体怎么变,1rem 永远等于当前 html 元素的 font-size 值。你改一次 document.documentElement.style.fontSize,所有 rem 尺寸自动重算。
常见错误现象:
- 写成
body { font-size: 14px; }再用em,结果子元素字体层层叠加,最后按钮宽变成设计稿的 1.8 倍 - 用
%设宽度,但父容器没设width,实际渲染为auto,百分比失效
而 rem 只要确保 html 根字体设对,后面全是确定性计算。
JS 动态设置 font-size 的关键公式
核心不是“写 JS”,而是把屏幕宽度映射到一个可稳定换算的基准值。通用公式是:
document.documentElement.style.fontSize = window.innerWidth / designWidth * baseSize + 'px'
其中:
-
designWidth是设计稿宽度(常见 375、750) -
baseSize是你约定的“1rem = ?px”,比如设为100,那 375px 屏宽下1rem = 100px,方便设计师给的150px直接写成1.5rem - 必须监听
resize和orientationchange,横竖屏切换时window.innerWidth会变
别漏掉 DOMContentLoaded 阶段就执行一次,否则首屏可能按默认 16px 渲染再闪动。
viewport meta 标签是前提,不是可选项
没有这个,rem 计算再准也没用:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
原因:
- 不加
width=device-width,iOS Safari 会按 980px 渲染,window.innerWidth拿到的是 980,不是真实物理宽度 -
initial-scale=1.0确保页面不被缩放,否则 JS 算出的font-size和视觉比例对不上 - 去掉
user-scalable=no会影响体验,但若保留,需在无障碍测试中确认是否合规
CSS 中 rem 换算容易忽略的三个细节
设计师给的 px 值不能直接除以 100 就完事:
- 字体大小建议用
rem,但行高(line-height)推荐用无单位数值(如1.5),避免随根字体缩放后行距爆炸 - 边框(
border)慎用rem,0.5rem 在小屏上可能粗得像描边;更稳妥的是固定1px或用transform: scale(0.5)模拟 - 媒体查询(
@media)里的min-width仍要用px,因为媒体查询不响应font-size变化
真正麻烦的从来不是“怎么设 rem”,而是设计稿里那些没说明白的视觉边界、文字截断逻辑、以及 iOS 上 input 聚焦时 viewport 自动缩放导致的 window.innerWidth 瞬间跳变——这些没法靠一个 font-size 算式解决。











