返回首页

说说 em/px/rem/vh/vw 区别

问题解析

CSS 单位是样式的基础,不同单位有不同的计算基准和适用场景。面试考察这个问题,是想要了解候选人对响应式设计和可访问性的理解。

单位分类

类别 单位
绝对单位 px, pt, cm, mm, in
相对单位 em, rem, %, vw, vh, vmin, vmax, ex, ch

各单位详解

1. px(像素)

绝对单位,CSS 中最常用的单位。

.element {
  width: 100px;
  font-size: 16px;
}

特点

  • 精确控制,易于理解
  • 与设备像素的关系受 DPR 影响
  • 不利于响应式设计和可访问性

2. em

相对单位,相对于父元素的字体大小。

.parent {
  font-size: 16px;
}

.child {
  font-size: 1.5em;     /* 16px × 1.5 = 24px */
  padding: 2em;         /* 24px × 2 = 48px(相对于自身字体大小) */
}

特点

  • 继承父元素字体大小
  • 适合组件化开发
  • 嵌套层级深时计算复杂

em 的复杂继承

html { font-size: 16px; }

.level1 { font-size: 1.5em; }   /* 24px */
.level2 { font-size: 1.5em; }   /* 36px(24px × 1.5) */
.level3 { font-size: 1.5em; }   /* 54px(36px × 1.5) */

3. rem(root em)

相对单位,相对于**根元素(html)**的字体大小。

html {
  font-size: 16px;
}

.element {
  font-size: 1.5rem;    /* 16px × 1.5 = 24px */
  padding: 2rem;        /* 32px(始终基于 html 字体大小) */
}

特点

  • 计算基准统一,不层层继承
  • 适合整体布局控制
  • 是现代响应式开发的首选

** rem 方案**:

/* 基准设置 */
html {
  font-size: 62.5%;     /* 16px × 62.5% = 10px */
}

/* 使用 */
.element {
  width: 30rem;         /* 300px */
  font-size: 1.4rem;    /* 14px */
  padding: 2rem;        /* 20px */
}

4. vw(viewport width)

视口宽度单位,1vw = 视口宽度的 1%。

.element {
  width: 50vw;          /* 视口宽度的 50% */
  font-size: 2vw;       /* 视口宽度的 2% */
}

特点

  • 相对于视口,无视父元素
  • 适合流体布局
  • 字体大小随视口变化,可能过大或过小

5. vh(viewport height)

视口高度单位,1vh = 视口高度的 1%。

.hero {
  height: 100vh;        /* 视口高度的 100% */
  min-height: 100vh;    /* 确保至少一屏高 */
}

移动端 vh 问题

移动端浏览器工具栏会占用视口高度,导致 100vh 可能超出可视区域。

解决方案

/* 新 CSS 单位 */
.element {
  height: 100dvh;       /* 动态视口高度,推荐 */
}

/* 或 JS 方案 */
:root {
  --vh: 1vh;
}

.element {
  height: calc(var(--vh, 1vh) * 100);
}
window.addEventListener('resize', () => {
  document.documentElement.style.setProperty('--vh', window.innerHeight * 0.01 + 'px');
});

单位对比

单位 相对基准 优点 缺点 适用场景
px 无(绝对) 精确、可控 不灵活 边框、阴影等固定值
em 父元素字体 组件化 嵌套复杂 按钮内边距等
rem 根元素字体 统一、响应式 需要计算 布局、字体大小
vw 视口宽度 流体布局 可能失控 视口相关尺寸
vh 视口高度 全屏布局 移动端问题 全屏区块

深入理解

单位混合使用

.card {
  /* 布局用 rem */
  padding: 2rem;
  margin-bottom: 1.5rem;

  /* 边框用 px */
  border: 1px solid #ddd;
  border-radius: 4px;

  /* 字体用 rem */
  font-size: 1.6rem;

  /* 阴影用 px */
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

可访问性考虑

/* 不推荐:固定 px */
html { font-size: 10px; }

/* 推荐:百分比,尊重用户浏览器设置 */
html { font-size: 62.5%; }   /* 基于用户默认 16px */

/* 更好的推荐:配合媒体查询 */
html {
  font-size: 62.5%;
}

@media (prefers-reduced-motion: reduce) {
  html { font-size: 100%; }
}

clamp() 流体排版

/* 字体大小在 16px 到 24px 之间,首选 2vw */
h1 {
  font-size: clamp(16px, 2vw, 24px);
}

/* 响应式宽度 */
.container {
  width: clamp(320px, 90vw, 1200px);
  margin: 0 auto;
}

现代布局最佳实践

/* 1. 根元素基准 */
html {
  font-size: 62.5%;     /* 1rem = 10px */
}

@media (max-width: 768px) {
  html {
    font-size: 56.25%;   /* 1rem = 9px */
  }
}

/* 2. 布局用 rem */
.container {
  max-width: 120rem;     /* 1200px */
  padding: 0 2rem;       /* 0 20px */
}

/* 3. 间距用 rem */
.section {
  margin-bottom: 8rem;   /* 80px */
}

/* 4. 小元素用 px */
.border {
  border: 1px solid #ddd;
}

移动端适配方案

rem 方案

function setRem() {
  const designWidth = 375;           // 设计稿宽度
  const baseFontSize = 100;          // 1rem = 100px
  const width = document.documentElement.clientWidth;
  document.documentElement.style.fontSize = (width / designWidth * baseFontSize) + 'px';
}
window.addEventListener('resize', setRem);
/* 设计稿 750px,某元素 200px → 写 2rem */
.element {
  width: 2rem;          /* 200px */
}

vw 方案

/* 直接基于视口 */
.element {
  width: 53.333vw;      /* 200/375*100 */
}

/* 配合 CSS 变量 */
:root {
  --vw: 1vw;
}

.element {
  width: calc(200 * var(--vw));
}

面试要点

  1. 能够准确说出各单位的计算基准
  2. 理解 em 和 rem 的区别和使用场景
  3. 了解 vw/vh 的优缺点,特别是移动端 vh 的问题
  4. 知道 rem 方案的实现原理
  5. 了解 clamp() 函数的应用
  6. 理解为什么推荐 rem + px 混合使用