Skip to content

rem / em / vw 响应式布局单位详解

导航目录

核心概念

在移动端做响应式布局时,emremvw 都是相对单位。它们的差异在于参照物不同:字体大小、根元素或视口。

概览

单位参照对象适用场景
em当前元素的 font-size组件内部跟随文字大小变化的间距
rem根元素(html)的 font-size全站统一缩放的尺寸体系
vw视口宽度(100vw = 视口宽度)布局宽度、栅格、间距

em(相对当前元素的字体大小)

em 是相对当前元素font-size(更准确地说,是相对"当前元素计算后的字体大小")。

基础示例

html
<div class="parent">
  <div class="child">text</div>
</div>
css
.parent {
  font-size: 50px;
}
.child {
  font-size: 1em; /* 50px */
  padding: 0.5em; /* 25px */
}

注意

em 容易出现嵌套叠加:多层组件都用 em 改字体大小时,最终数值可能被层层放大/缩小,导致样式失控。

css
/* 嵌套叠加示例 */
.level1 {
  font-size: 2em;
} /* 2em = 32px (假设默认16px) */
.level2 {
  font-size: 2em;
} /* 2em = 64px (相对于父级32px) */
.level3 {
  font-size: 2em;
} /* 2em = 128px (相对于父级64px) */

rem(相对根元素 html)

rem(root em)是相对根元素html)的 font-size

基础示例

css
html {
  font-size: 100px;
}

.box {
  width: 1rem; /* 100px */
  padding: 0.5rem; /* 50px */
  font-size: 0.16rem; /* 16px */
}

核心优势

  • 适合做统一缩放:只要调整 html { font-size: ... },全站使用 rem 的尺寸会一起变化
  • 避免嵌套问题:与 em 不同,rem 始终相对于根元素,不受父元素影响

常见实践:移动端适配

javascript
// 根据屏幕宽度动态设置根字号
function setRem() {
  const designWidth = 750; // 设计稿宽度
  const baseFontSize = 100; // 1rem = 100px
  const scale = document.documentElement.clientWidth / designWidth;
  document.documentElement.style.fontSize = baseFontSize * scale + "px";
}

window.addEventListener("resize", setRem);
setRem();
css
/* 使用 CSS clamp() 函数(现代浏览器支持) */
html {
  font-size: clamp(12px, 2vw, 20px);
}

vw(相对视口宽度)

vw(viewport width)是相对视口宽度,视口宽度被均分为 100 份。

计算方式

假设视口宽度是 750px

  • 1vw = 750px / 100 = 7.5px
  • 10vw = 75px
  • 100vw = 750px(满屏宽度)

基础示例

css
.card {
  width: 50vw; /* 视口宽度的一半 */
  padding: 2vw; /* 随视口宽度变化的间距 */
  font-size: 4vw; /* 随视口宽度变化的字体大小 */
}

优势

vw 不依赖字体大小,天然跟着屏幕宽度变化;做宽度、间距、布局比例时很顺手。


对比与选型

使用场景推荐

场景推荐单位原因
布局宽度 / 栅格 / 间距vw直接关联视口,响应式最自然
全站统一缩放的尺寸rem通过根字号统一控制
组件内部跟随文字的间距em按钮 padding 随字体变大
字体大小rempx保证可读性,避免过小

混合使用示例

css
.component {
  /* 布局宽度用 vw */
  width: 90vw;
  max-width: 1200px;

  /* 内部间距用 rem */
  padding: 1rem;
  margin: 0.5rem;

  /* 字体大小用 rem */
  font-size: 1rem;

  /* 行高用无单位数值 */
  line-height: 1.5;
}

常见坑与解决方案

1. 移动端视口配置

问题:没有正确的 viewport 配置,vw 的计算可能与你预期不一致。

解决方案

html
<meta
  name="viewport"
  content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>

2. em 的嵌套叠加

问题:组件库/多层嵌套时,em 的值会被层层放大/缩小。

解决方案

  • 组件库推荐使用 rempx
  • 如需使用 em,确保组件内部有明确的字体大小基准

3. 字体大小过小

问题:使用 vw 设置字体时,在小屏幕上可能过小。

解决方案

css
/* 使用 clamp() 限制字体大小范围 */
.text {
  font-size: clamp(14px, 2vw, 18px);
}

/* 或使用媒体查询 */
.text {
  font-size: 2vw;
}
@media (max-width: 375px) {
  .text {
    font-size: 14px;
  }
}

4. 1px 边框问题

问题:在高清屏上,1px 边框可能显示过粗。

解决方案

css
/* 使用 transform: scale() */
.border-1px {
  position: relative;
}
.border-1px::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 1px;
  background: #ccc;
  transform: scaleY(0.5);
  transform-origin: 0 0;
}

最佳实践总结

  1. 移动端适配首选 rem:通过动态设置根字号实现等比缩放
  2. 流式布局用 vw:适合不需要严格还原设计稿的场景
  3. 组件内部用 em:让间距随字体大小自然变化
  4. 限制字体大小范围:使用 clamp() 或媒体查询防止字体过小
  5. 设置最大宽度:使用 max-width 防止在大屏幕上内容过宽
css
/* 完整的移动端适配方案 */
html {
  font-size: calc(100vw / 7.5); /* 以 750px 设计稿为基准,1rem = 100px */
}

body {
  max-width: 750px;
  margin: 0 auto;
  font-size: 0.28rem; /* 28px */
}

.container {
  width: 100%;
  padding: 0.3rem;
}