rem基于根元素font-size,em基于父元素font-size;rem全局统一、无继承累乘,适合响应式;em逐层继承相乘,易失控,适合局部比例控制。

rem 是相对于根元素 font-size,em 是相对于父元素 font-size
这是最根本的区别。浏览器计算 1rem 时,只看 html 元素的 font-size 值;而计算 1em 时,会向上查找**直接父元素**的 font-size,逐层继承、逐层相乘。
常见错误现象:div > p > span 中,如果 div 设了 font-size: 20px,p 设了 font-size: 1.5em(即 30px),那么 span 里写 margin: 1em,实际是 30px,不是 20px —— 很多人误以为 em 总是“继承初始值”,其实它实时响应父级当前生效的字体大小。
使用场景差异:
-
rem适合全局缩放控制:比如整站字体/间距统一放大 20%,只需改一句html { font-size: 19.2px }(原 16px × 1.2) -
em适合局部比例关系:比如按钮内边距随自身字号变化,.btn { font-size: 14px; padding: 0.6em 1em; },换到标题栏里字号变大,内边距也等比撑开
嵌套层级深时,em 容易“指数级放大”,rem 不会
当多个嵌套元素都用 em 设置 font-size,结果极易失控。例如:
立即学习“前端免费学习笔记(深入)”;
html { font-size: 16px }
.section { font-size: 1.2em } /* 19.2px */
.article { font-size: 1.2em } /* 19.2 × 1.2 = 23.04px */
.title { font-size: 1.5em } /* 23.04 × 1.5 ≈ 34.56px */三层嵌套后,title 字号已是原始的 2.16 倍。而同样结构下用 rem:
.section { font-size: 1.2rem } /* 19.2px */
.article { font-size: 1.2rem } /* 还是 19.2px */
.title { font-size: 1.5rem } /* 还是 24px */所有元素都锚定在根字体上,互不影响。这也是为什么现代响应式框架(如 Bootstrap 5+)默认用 rem 做基础尺寸单位。
移动端适配中,rem 需配合动态 html font-size,em 则基本不参与
主流 rem 适配方案本质是:让 1rem = 视口宽度 / 10(即 10 等份)。这需要 JS 或媒体查询动态设置 html 的 font-size:
- JS 方案:
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px'; - CSS 方案:
@media (max-width: 750px) { html { font-size: 14px; } }
而 em 没法绑定视口,它只认父级字体,所以几乎不用于设备宽度适配。强行用 em 做响应式,意味着你得在每一层父容器上加 media query,维护成本爆炸。
兼容性与调试:rem 在 IE9+ 完全支持,em 更老但行为更难预测
rem 是 CSS3 新增单位,IE9 开始支持,目前所有现代浏览器无兼容问题;em 虽然 IE6 就支持,但它的“相对性”在复杂继承链中极难调试 —— 尤其当父元素 font-size 来自继承、重置、或被 !important 干扰时,开发者很难一眼判断当前 1em 究竟是多少像素。
建议调试方式:
- Chrome DevTools 中选中元素 → 右侧 Styles 面板 → 找到对应属性,悬停看 computed 值旁的小箭头,点开会显示“computed as Xpx”
- 临时加
outline: 1px solid red辅助观察盒模型缩放是否符合预期
真正容易被忽略的是:rem 的基准一旦由 JS 动态设置,就必须确保 JS 执行早于 CSS 解析(比如放在 <head> 内 inline 执行),否则首屏可能闪动;而 em 虽不依赖 JS,但它的“隐式依赖”往往在重构时才暴露出来 —— 比如删掉一个中间父容器,子元素尺寸就突变。


















