rem可实现真正等比缩放,em因依赖父级font-size、嵌套后失控而无法全局等比;rem需动态设置html字体大小、配合viewport标签,并统一所有尺寸单位才能生效。

rem 可以实现真正意义上的等比缩放,em 不行——它依赖父级 font-size,嵌套越深越不可控,根本没法做全局缩放。
为什么 em 不能用于等比缩放
em 是相对于当前元素或父元素 font-size 的单位,不是固定锚点。只要中间某一层 font-size 被改了(比如某个组件设了 font-size: 14px),它下面所有用 em 写的 width、padding 就会连锁错乱。
常见错误现象:
- 同一组按钮在不同层级容器里宽高不一致
- 文字缩放正常,但边距忽大忽小,布局“抖动”
- 横竖屏切换后部分区域错位,查不到源头
如果你只是想让某一块模块内部相对缩放(比如弹窗内容区随标题字号变化),em 可以用;但全页面等比缩放,必须放弃 em。
立即学习“前端免费学习笔记(深入)”;
rem 等比缩放的唯一可靠起点:动态设置 document.documentElement.style.fontSize
rem 的缩放能力只来自一个动作:JavaScript 动态改 html 元素的 font-size。写死 html { font-size: 37.5px } 或用媒体查询分段设,都不是等比——那是断点式适配,中间会跳变。
标准计算逻辑(以 750px 设计稿为例):
-
baseWidth = 750:UI 给的设计稿宽度,必须对齐 -
baseFontSize = 100:约定“750px 宽度下,1rem = 100px”,这样设计稿上 75px 直接写成0.75rem fontSize = document.documentElement.clientWidth / baseWidth * baseFontSize
执行时机很重要:
- 必须在
DOMContentLoaded后立即执行一次 - 监听
resize和orientationchange,否则横屏失效 - iOS Safari 加载瞬间可能没触发
resize,建议加个setTimeout(() => setRem(), 0)补漏
viewport 标签没配对,rem 就是空中楼阁
不加或加错 <meta name="viewport">,所有 rem 计算都基于错误的布局视口(比如默认 980px),结果就是页面整体被压缩、文字小得看不清、横向滚动条意外出现。
这行必须手写进 <head>,且不能被 JS 动态覆盖:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
关键点:
-
width=device-width是核心,它让布局视口宽度 = 设备 CSS 像素宽度 -
initial-scale=1.0防止首次加载时字体突变 - 不要加
minimum-scale,某些安卓 WebView 会因此忽略initial-scale
哪些属性该用 rem,哪些坚决不能碰
rem 是尺寸缩放单位,不是万能单位。混用会破坏一致性,尤其在小屏下放大 border 或缩小 line-height 会导致可读性崩塌。
推荐用 rem 的属性:
font-size-
width/height -
margin/padding border-radius
明确禁用 rem 的属性:
-
line-height:用无单位值(如1.5),避免叠加缩放 -
border-width:固定写1px,否则小屏下可能缩到 0.2px 不可见 -
background-size、box-shadow偏移:px 更可控 -
transform: scale():这是视觉缩放,和 rem 的布局缩放逻辑冲突
最常被忽略的一点:rem 缩放生效的前提是「所有尺寸都统一走这套换算」。只要有一个地方漏写了 rem、或者用了 px 固定值,整个等比链条就断了——缩放后那个元素会“钉”在原尺寸,显得格外突兀。


















