viewport meta 标签必须写全且正确,否则 rem 失效;核心是 width=device-width 和 initial-scale=1.0,需避免固定宽度、动态覆盖及执行时机错误,并配合 box-sizing: border-box 和合理根字号设置。

viewport meta 标签必须写全,否则 rem 全部失效
不加或写错 <meta name="viewport">,rem 就是空中楼阁。浏览器默认用 980px 布局视口渲染,所有基于视口的计算(包括 rem 的根字号)都跑偏。
常见错误现象:页面整体被压缩、文字小得看不清、横向滚动条意外出现、点击区域错位。
-
width=device-width是核心,它让布局视口宽度 = 设备 CSS 像素宽度 -
initial-scale=1.0防止首次加载时缩放导致字体突变 -
maximum-scale=1.0, user-scalable=no必须带上——iOS 双击放大后视口缩放值变化,但html字号不变,rem 元素就集体“失重” - 别写
width=375这种固定值,它在非 375px 宽设备上强制缩放,rem 失去意义 - 不能用 JS 动态覆盖这行 meta,除非你明确知道在改什么
根字号设置必须同步执行,避免首屏闪动
很多项目用 JS 动态设 document.documentElement.style.fontSize,但线上出问题往往不是算法错,而是执行时机不对。
典型错误:JS 放在 </body> 底部或监听 DOMContentLoaded,导致首屏先按默认 16px 渲染,再重算,肉眼可见闪动。
立即学习“前端免费学习笔记(深入)”;
- 必须在
<head>内同步执行,或确保 JS 在 DOM 构建前运行(如 IIFE 包裹) - 别用
window.screen.width直接除——它返回物理像素宽(iPhone 13 是 1170),不是 CSS 像素(390),会翻倍放大 - 正确取值应是
document.documentElement.clientWidth或window.innerWidth(注意:后者含滚动条宽度,需容错) - 必须监听
resize和orientationchange,横竖屏切换时视口尺寸突变,不重算会导致文字突然撑开或压缩
box-sizing: border-box 是 rem 布局的隐性前提
设计师给的按钮高 44px,指的是包含内边距和边框的总高;但默认 box-sizing: content-box 会让 padding 和 border 额外增加元素总宽,实际内容区只剩不到 40px,按钮看起来就被“削薄”了。
- 全局加
* { box-sizing: border-box },别漏掉伪元素::before/::after - 第三方 UI 库(如 vant、nutui)内部可能覆盖
box-sizing,需单独重置其组件的box-sizing - 避免在
body上设min-width或max-width,它会干扰 rem 缩放后的实际渲染宽度
vw 替代 JS 动态 rem 更轻量,但要注意精度陷阱
想省掉 JS?vw 是更简方案:一行 CSS 就够,无运行时开销,兼容 iOS 8+/Android 4.4+。
典型写法(750px 设计稿 → 100vw = 750px → 1px = 100vw / 750):
html { font-size: calc(100vw / 7.5); } /* 1rem = 100px (设计稿单位) */这样写后,设计稿上量的 375px 宽度,直接写 width: 3.75rem;16px 字体写 font-size: 0.16rem。
- 别用
font-size: 13.333vw这种写法——小数精度在低端机上会导致 1px 偏差累积 - iOS Safari 横屏切换时可能有短暂重排,可加
@media (orientation: landscape)微调 - DPR 不影响 rem 计算本身,但会影响图片清晰度和 1px 边框——这是另一个维度的问题,别混在一起调
真正容易被忽略的不是公式怎么写,而是 viewport 是否真生效、JS 执行是否早于首屏渲染、box-sizing 是否被第三方库悄悄覆盖——这些点一错,整个 rem 体系就无声崩塌。


















