css 使用 rem 和 em 单位_实现灵活的响应式布局

12次阅读

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

css 使用 rem 和 em 单位_实现灵活的响应式布局

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 容器里,会因父级字号变动导致意料外的缩放链。

rem + viewport 缩放容易踩的坑

很多方案同时设置 和动态 rem,但 ios safari 在横竖屏切换时可能触发双倍缩放,导致 clientWidth 计算失真。

规避方法:

  • 避免在 viewport 中写 maximum-scaleuser-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、以及设计系统对缩放一致性的要求程度。

text=ZqhQzanResources