rem是相对于根元素font-size的单位,1rem默认为16px,通过动态设置document.documentElement.style.fontSize实现响应式;em则相对于父元素font-size,易因嵌套连乘失控,适合局部适配;clamp()提供无JS、无FOUC的响应式方案,但需考虑兼容性。

rem 是相对于根元素 font-size 的单位
浏览器默认根元素 的 font-size 是 16px,所以 1rem 默认等于 16px。只要动态改 document.documentElement.style.fontSize,所有用 rem 的尺寸就同步缩放——这是实现响应式字体和间距的核心机制。
常见做法是在 中插入一段 JS,根据屏幕宽度按比例设置根字号,比如:
function setRootFontSize() {
const width = document.documentElement.clientWidth;
const base = 375; // 设计稿宽度
const scale = width / base;
document.documentElement.style.fontSize = `${scale * 16}px`;
}
setRootFontSize();
window.addEventListener('resize', setRootFontSize);注意:这段逻辑必须在 DOM 加载前或早期执行,否则页面可能闪动;如果用 Webpack/Vite,建议封装为自执行函数并确保早于 CSS 加载。
em 是相对于父元素 font-size 的单位
em 的值取决于**直接父元素**的 font-size,逐层继承、容易嵌套失控。比如父元素是 1.2em(即 19.2px),子元素写 1.2em 就变成 19.2 × 1.2 ≈ 23px,再下一层继续乘——这不是“缩放”,而是“连乘”,不适合全局响应式控制。
立即学习“前端免费学习笔记(深入)”;
但 em 在局部场景仍有价值:
- 按钮内边距跟随文字大小变化:
padding: 0.5em 1em; - 图标尺寸与文字对齐:
font-size: 1.2em;配合line-height: 1; -
伪元素尺寸适配文字:
::before { font-size: 0.8em; }
别用 em 控制布局容器宽高,尤其在 flex/grid 容器里,会因父级字号变动导致意料外的缩放链。
1、系统采用.net2.0开发,数据库access2、三层架构,数据层、逻辑层和表示层分离3、系统完全使用div+css布局,可以灵活处理界面4、技术特点: 使用模板页,大大减少代码量 动态生成竖向导航菜单 ul li实现表格 各种自定义用户空间 Reapter等数据控件的灵活运用
rem + viewport 缩放容易踩的坑
很多方案同时设置 和动态 rem,但 iOS Safari 在横竖屏切换时可能触发双倍缩放,导致 clientWidth 计算失真。
规避方法:
- 避免在
viewport中写maximum-scale或user-scalable=no,它们会干扰系统缩放逻辑 - 用
window.innerWidth替代document.documentElement.clientWidth做计算基准(更稳定) - 监听
orientationchange事件,而非仅靠resize - 对 PC 端做降级:媒体查询判断
min-width: 768px后固定根字号为16px,防止桌面端误缩放
现代项目建议用 clamp() 替代纯 rem 方案
CSS clamp() 能在最小值、首选值、最大值之间平滑过渡,比 JS 动态改根字号更轻量、无 FOUC、支持服务端渲染:
p {
font-size: clamp(14px, 2.5vw, 18px);
}
.card {
padding: clamp(12px, 3vw, 24px);
}但要注意兼容性:clamp() 在 Safari 13.1+、Chrome 88+、Firefox 79+ 支持;老版本需 fallback 到 rem 或媒体查询。
真正复杂的地方不在单位本身,而在「何时该用 rem、何时该用 em、何时该放弃它们直接上视口单位或 clamp」——这取决于你是否需要 JavaScript 参与控制、是否要兼顾 SSR、以及设计系统对缩放一致性的要求程度。









