px、rem、em、vh、vw 之间的区别到底是什么?
Category(分类): CSS Status: 已整理
CSS 长度单位大致可以分为绝对长度和相对长度。不同单位的关键区别不只是“大小是否固定”,还在于它们参考的对象不同:
px:CSS 像素;rem:根元素的字体大小;em:根据使用它的属性和元素的字体大小计算;vh、vw:视口尺寸;%:参考对象由具体 CSS 属性决定。
理解参考对象,是正确使用这些单位的关键。
一、为什么需要相对长度
如果所有尺寸都使用固定的 px,在不同屏幕尺寸、字体设置和布局环境下,页面不一定能保持合适的比例。例如,缩小视口时,我们通常不仅希望盒子的宽高变化,也希望间距、字体和组件尺寸能够按照一定规则调整。
相对长度可以让尺寸与根字体、局部组件、视口或包含块建立关系,从而更容易实现响应式布局。但相对单位并不意味着所有内容都会自动适配,仍然需要结合媒体查询、容器查询、clamp()、最小/最大尺寸和内容换行策略。
二、绝对长度单位:px
1. px 是 CSS 像素
px 是 CSS 中最常用的绝对长度单位:
.box {
width: 160px;
height: 100px;
}
这里的 px 是 CSS 像素,不是屏幕上的物理像素,也不一定等于设备硬件像素。实际显示还会受到以下因素影响:
- 设备像素比
devicePixelRatio; - 浏览器缩放;
- 操作系统显示缩放;
- 用户代理和显示设备。
因此,1px 在 CSS 计算中是稳定的参考长度,但不能简单理解为显示屏上的一个物理像素点。
2. 其他绝对长度
CSS 还提供了 cm、mm、Q、in、pt 和 pc 等绝对长度单位。它们在 CSS 规范中有相互换算关系,但在屏幕设备上不一定能准确对应现实中的物理长度。
在网页布局中,px 通常用于:
- 细边框;
- 图标尺寸;
- 阴影偏移;
- 精确的最小尺寸;
- 不希望随字体或容器缩放的细节。
三、rem:相对于根元素字体大小
rem 是 root em 的缩写,始终参考根元素的计算字体大小。根元素通常是 <html>,也可以通过 :root 选择器设置。
1. rem 与 px 的计算关系
在常见浏览器默认设置下,根元素的字体大小通常是 16px:
:root {
font-size: 16px;
}
.box {
width: 10rem; /* 160px */
font-size: 1rem; /* 16px */
}
计算关系是:
实际 CSS 像素值 = rem 数值 × 根元素的计算字体大小
例如:
:root {
font-size: 20px;
}
.box {
width: 2rem; /* 40px */
}
但根元素的默认字体大小可能受到用户设置、浏览器设置和页面样式影响,不应把 16px 视为永远固定的值。
2. 修改 rem 的参考值
可以在根元素上设置字体大小:
html {
font-size: 32px;
}
.box {
width: 10rem; /* 320px */
}
也可以使用 :root:
:root {
font-size: 32px;
}
不能通过普通父元素改变某个后代的 rem 参考值。下面的 .parent 不会改变 .child 使用的 rem 基准:
html {
font-size: 16px;
}
.parent {
font-size: 32px;
}
.child {
width: 2rem; /* 仍然是 32px,而不是 64px */
}
如果希望尊重用户的默认字体设置,可以使用:
html {
font-size: 100%;
}
此时 1rem 通常等于浏览器当前的默认字体大小。
3. rem 示例
<div class="div-rem">rem</div>
html {
font-size: 16px;
}
.div-rem {
width: 10rem;
height: 10rem;
font-size: 1rem;
background-color: #a58778;
}

使用 rem 可以让页面中的字号、间距和组件尺寸共享一个全局缩放基准:
:root {
font-size: 16px;
}
.page {
padding: 2rem;
}
.title {
font-size: 1.5rem;
}
需要注意,在根元素的 font-size 声明中使用 rem 有特殊计算规则,不建议写成:
html {
font-size: 2rem;
}
如果需要设置根字体大小,使用 px、百分比或其他明确的方式更容易理解。
四、em:相对于上下文中的字体大小
em 的参考规则需要根据使用它的属性区分。
1. 用在 font-size 中
当 em 用在元素的 font-size 声明中时,通常参考父元素的计算字体大小:
<div class="parent">
I'm parent div set to 20px.
<div class="child">
I'm the child div set to 2em, i.e. 40px.
</div>
</div>
.parent {
font-size: 20px;
}
.child {
font-size: 2em; /* 2 × 20px = 40px */
}

如果父元素没有显式设置字体大小,就会使用继承链上得到的计算值;如果祖先都没有修改,通常会接近浏览器的默认字体大小。
2. 用在其他属性中
对于 width、height、padding、margin 和多数边框宽度等属性,em 通常参考当前元素的计算字体大小:
.box {
font-size: 20px;
width: 10em; /* 200px */
padding: 2em; /* 40px */
border-width: 0.1em; /* 2px */
}
因此,不能笼统地说 em 永远等于父元素的字体大小。
3. 元素自身设置字体大小的情况
.div-em {
font-size: 32px;
width: 10em; /* 320px,width 使用当前元素字体大小 */
height: 10em; /* 320px */
background-color: aquamarine;
}
但对于下面的 font-size 声明,2em 仍然参考父元素的字体大小,而不是当前元素未来的字体大小:
.child {
font-size: 2em;
}

这是因为计算 font-size 时,当前元素的字体大小还没有确定。
4. 嵌套继承会产生累积效果
.grandparent {
font-size: 20px;
}
.parent {
font-size: 1.5em; /* 30px */
}
.child {
font-size: 2em; /* 60px */
}
em 的灵活性很高,但深层嵌套时计算链可能变得复杂,需要注意实际的计算字体大小。
五、rem 与 em 的区别
| 单位 | 主要参考对象 | 常见特点 |
|---|---|---|
rem | 根元素的计算字体大小 | 全局统一,嵌套层级不会改变基准 |
em 用于 font-size | 父元素的计算字体大小 | 会沿继承关系累积 |
em 用于多数其他属性 | 当前元素的计算字体大小 | 适合组件内部按字号缩放 |
一个常见误解是“rem 继承父元素”。实际上,font-size 属性本身可以继承,但 rem 的参考基准始终是根元素。
六、em 和 rem 的使用场景
1. 适合使用 rem 的场景
rem 适合全局设计令牌和页面级尺寸:
:root {
font-size: 100%;
}
.page {
padding: 2rem;
}
.heading {
font-size: 2rem;
}
常见用途包括:
- 页面级字号;
- 全局间距;
- 设计系统中的尺寸令牌;
- 希望统一缩放的组件尺寸。
2. 适合使用 em 的场景
em 适合组件内部与自身字体大小建立比例:
.button {
font-size: 1rem;
padding: 0.75em 1.25em;
border-radius: 0.5em;
}
.button--large {
font-size: 1.25rem;
}
改变按钮字号时,内边距和圆角也会按组件自身的字体大小一起变化。
3. 不要为了“响应式”大量修改根字号
过去常见的做法是根据视口宽度用 JavaScript 或复杂公式不断修改 html 的 font-size。现代 CSS 通常可以使用:
.title {
font-size: clamp(1.5rem, 1rem + 2vw, 3rem);
}
clamp(min, preferred, max) 可以在范围内平滑缩放,同时设置最小值和最大值,通常比无上限地修改根字体大小更容易维护。
七、vh 和 vw:相对于视口
vh 和 vw 的参考对象是视口(viewport),不是父元素:
1vh:视口高度的 1%;1vw:视口宽度的 1%;100vh:传统意义上视口高度的 100%;100vw:视口宽度的 100%。
示例:
.viewport-box {
width: 10vw; /* 视口宽度的 1/10 */
height: 10vh; /* 视口高度的 1/10 */
background-color: pink;
}
移动端视口高度
移动端浏览器的地址栏、工具栏会展开和收起,传统 100vh 在不同浏览器或不同状态下可能无法准确表示当前可见区域。现代 CSS 提供了三组视口尺寸单位:
svh:小视口高度;lvh:大视口高度;dvh:动态视口高度。
例如:
.page {
min-height: 100dvh;
}
如果页面需要避免浏览器 UI 覆盖,应该根据实际交互选择 svh、lvh 或 dvh,必要时再结合安全区域:
.page {
min-height: 100dvh;
padding-bottom: env(safe-area-inset-bottom);
}
100vw 与滚动条
在部分浏览器中,100vw 可能包含垂直滚动条占用的区域,从而造成轻微横向溢出。需要填充普通内容区域时,通常可以使用:
.full-width {
width: 100%;
}
八、vh、vw 与百分比的区别
百分比的参考对象由具体 CSS 属性决定;vh 和 vw 则参考视口。
<div class="parent">
<div class="percentage-child"></div>
</div>
<div class="viewport-box"></div>
.parent {
width: 400px;
height: 200px;
background-color: #f5f5f5;
}
.percentage-child {
width: 50%;
height: 50%;
background-color: aliceblue;
}
.viewport-box {
width: 50vw;
height: 50vh;
background-color: pink;
}
在这个例子中:
.percentage-child的宽高参考包含块的宽高;.viewport-box的宽高参考视口宽高;- 如果百分比高度的包含块高度不确定,
height: 50%可能无法得到预期的固定结果。
但“百分比总是参考父元素”也不准确。例如:
width百分比通常参考包含块宽度;height百分比需要包含块有确定高度;padding和margin的百分比通常参考包含块的宽度;font-size百分比参考父元素字体大小。
九、其他常见相对单位
1. vmin 和 vmax
.square {
width: 50vmin;
height: 50vmin;
}
vmin:视口宽度和高度中较小值的 1%;vmax:视口宽度和高度中较大值的 1%。
它们适合创建始终基于视口短边或长边缩放的图形。
2. ch 和 ex
ch大致参考当前字体中字符0的 advance measure,适合控制文本行宽;ex参考当前字体的 x-height,实际值依字体而异。
例如:
.article {
max-width: 70ch;
}
ch 不是严格的“一个汉字宽度”,不同字体、字符和语言环境下都会有差异。
十、单位选择建议
| 场景 | 常见选择 | 说明 |
|---|---|---|
| 细边框、图标细节 | px | 需要稳定的 CSS 像素尺寸 |
| 页面级字号和间距 | rem | 统一参考根元素字体大小 |
| 组件内部间距 | em | 随组件字体大小一起缩放 |
| 视口相关布局 | vw、vh、dvh | 参考视口,移动端要考虑动态视口 |
| 相对于容器的尺寸 | % | 参考对象取决于具体属性 |
| 文本阅读宽度 | ch、rem | 应结合实际字体和内容测试 |
| 有上下限的流式尺寸 | clamp() 与相对单位 | 避免尺寸无限缩放 |
不要把某一种单位当成所有场景的固定答案。网页还需要考虑内容长度、用户字体设置、浏览器缩放、可访问性和最小/最大尺寸。
十一、常见问题
1. 为什么设置 height: 100% 没有效果?
因为百分比高度通常需要包含块具有确定的高度:
html,
body {
height: 100%;
}
.page {
height: 100%;
}
如果祖先高度都是 auto,子元素的百分比高度可能无法按预期解析。
2. 为什么 em 嵌套后越来越大?
因为 font-size 中的 em 会参考父元素字体大小,多个嵌套层级会产生累积:
.parent {
font-size: 1.5em;
}
.child {
font-size: 1.5em;
}
组件内部需要稳定基准时,可以使用 rem,或者在组件根节点明确设置 font-size。
3. 为什么 100vw 会产生横向滚动?
可能是 100vw 包含了垂直滚动条宽度,也可能是元素同时存在边距、边框或自身宽度计算超出容器。可以检查:
* {
box-sizing: border-box;
}
并在普通内容区域优先使用 width: 100%。
4. 相对单位会带来性能问题吗?
正常使用 em、rem、vh、vw 不应被简单归因于性能问题。更需要关注的是:
- 是否造成频繁的布局变化;
- 是否在 JavaScript 中高频修改样式;
- 是否产生大量复杂的嵌套计算;
- 是否因为内容溢出触发不必要的滚动和重排。
十二、总结
px是 CSS 像素,不等于设备物理像素;rem始终参考根元素的计算字体大小;em在font-size中通常参考父元素,在多数其他属性中通常参考当前元素的字体大小;vh和vw参考视口,不参考普通父元素;- 移动端全屏布局应根据情况使用
svh、lvh或dvh; - 百分比的参考对象取决于具体属性,不能统一理解为父元素尺寸;
rem适合全局设计令牌,em适合组件内部缩放;clamp()可以限制流式尺寸的上下限;- 单位选择应同时考虑响应式布局、内容、用户设置和可访问性。