rem适配失效的根本原因是html的font-size未动态更新或更新时机错误;必须用JS根据clientWidth实时计算并监听resize和orientationchange事件,配合正确viewport设置。

rem 本身不跨屏,真正起作用的是你动态设置的 document.documentElement.style.fontSize —— 不设它,rem 就是静态的 16px,跟 px 没区别。
为什么 rem 在不同手机上尺寸没变?
常见错误现象:写了 font-size: 1.5rem,但 iPhone 12 和 Redmi Note 12 上文字一样大;横竖屏切换后布局错位;缩放页面时元素突兀跳变。
根本原因只有两个:
① html 元素的 font-size 没被 JS 动态更新;
② 更新时机不对,或漏监听关键事件。
必须明确:rem 只是“计算单位”,不是“适配方案”。它永远等于当前 document.documentElement.style.fontSize 的值。这个值默认是浏览器设定(通常 16px),不会自己响应屏幕变化。
立即学习“前端免费学习笔记(深入)”;
实操建议:
- 别在 CSS 里写死
html { font-size: 16px; }或100%,这等于放弃适配 - 首次渲染前就必须设好根字号,否则首屏按 16px 渲染,再改会闪一下
- 必须同时监听
resize和orientationchange,后者专治横竖屏切换失效问题 - 用
clientWidth(不含滚动条)而非innerWidth,移动端更准;PC 端偏差可接受
怎么算出正确的 html font-size?
核心公式取决于设计稿基准宽度。如果设计稿是 750px 宽,推荐用:document.documentElement.style.fontSize = document.documentElement.clientWidth / 750 * 100 + 'px';
这样在 750px 屏上,1rem = 100px;设计师标 “300px” 的按钮,你直接写 width: 3rem 即可。
注意点:
- 若设计稿是 375px,就把 750 换成 375,再把乘数改成 50(保持 1rem = 50px),否则换算比例全乱
- 别用
devicePixelRatio直接乘——DPR 是物理像素比,不是布局缩放依据;rem 适配靠逻辑像素,不是物理像素 - 不要在 JS 里用
getComputedStyle(document.documentElement).fontSize反查,这是读取结果,不是设置依据
哪些 CSS 属性该用 rem,哪些坚决不能碰?
混用会导致尺寸叠加、小屏下不可见、行高爆炸等实际问题。
该用(等比缩放合理):
-
font-size、width/height -
margin/padding、border-radius
不该用(已有相对语义或固定物理意义):
-
line-height:必须用无单位数值(如line-height: 1.5),否则会随根字号二次放大 -
border-width:比如border: 1px solid #ccc写成border: 0.01rem solid #ccc,小屏下可能缩到 0.2px,视觉消失 -
box-shadow偏移、transform: scale()、background-size:这些属性本身带缩放含义,再套 rem 容易失控
要不要加节流?怎么加才不丢事件?
不加节流,双指缩放、快速拖拽窗口时会高频触发重排,卡顿明显;但节流太狠,又可能漏掉横竖屏切换这种关键帧。
实操建议:
- 用 100ms 节流(非防抖),保证每 100ms 至少执行一次,既控频又保敏
- 首次进入立即执行一次,不等事件 —— 放在
DOMContentLoaded或requestAnimationFrame第一帧 - iOS Safari 初次加载常不触发
resize,所以必须主动调用一次计算函数 - 安卓 WebView 对
resize支持弱,orientationchange是兜底关键
最易被忽略的点:viewport meta 标签必须存在且正确,否则 clientWidth 返回值不可信。务必写:<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">。没有它,整个 rem 适配链就断在第一步。


















