HandyTools Hub

← 全部指南

CSS 单位详解:px、rem、em、%,以及什么时候该用哪一个

2026-08-24

font-size: 16pxfont-size: 1rem 可能渲染得一模一样——直到它们不一样。你选的单位不是口味,而是一条解析规则:它决定这个长度对什么求值,也就决定了浏览器缩放、根字号变化、父元素变化或视口变化时会发生什么。大多数”布局莫名其妙就坏了”的 CSS bug 其实是单位 bug。本文给你一张决策表,让你第一次就选对。

绝对与相对

每条 CSS 长度要么是绝对的,要么是相对的:

  • 绝对单位(px,以及面向打印的 ptcmmmin)是固定的。16px 永远是 16 CSS 像素,不随任何东西缩放。
  • 相对单位对别的东西求值:根字号(rem)、元素自身字号(em)、父元素(%)、视口(vwvhdvh)、或字体度量(chex)。

一旦缩放或布局变化,绝对单位原地不动,相对单位跟着动。这正是本文的工作——为每个属性决定它想要哪种行为。

px:设计基线

像素是设计单位:大多数设计稿以 px 交付,而 1px 是边框、发丝分隔线和盒阴影偏移的清晰度下限。

border: 1px solid #ddd;        /* 永远是一条利落的线 */
box-shadow: 0 1px 2px rgba(0,0,0,0.1);

陷阱是把 px 用在文字上。font-size: 14px 无视用户的字号偏好和浏览器缩放设置——所以 px 文字是经典的可访问性投诉。经验法则:结构与效果用 px,文字用 rem。

rem:锚定在根上的标尺

rem 是”root em”:一个 rem 等于 <html> 元素的 font-size。改根值,文档里所有 rem 一起缩放:

html { font-size: 100%; }       /* 默认 16px */
.title { font-size: 2rem; }     /* 根为 16px 时是 32px */
.body  { font-size: 1rem; }     /* 16px */

因为锚定在一个根值上,rem 给你整文档标尺:调根值,整套排版系统一起缩放。又因为浏览器和用户偏好会设置这个根值,rem 文字尊重用户字号设置——这就是可访问性默认。现代 CSS reset 鼓励文字用 rem 的原因也在此。(两个单位随手换算,用 Px to Rem Converter。)

em:相对元素自身——而且会复利

em 相对元素自身的 font-size。用在元素自身上很优雅:按钮的 padding: 0.5em 会随它的文字一起缩放。

危险在于嵌套里的复利em 对后代是按最近的祖先字号计算的,而祖先的 em 会相乘:

/* 每层都相乘:16px → 25.6px → 41px → 65px */
div { font-size: 1.6em; }  /* 在 16px 父级里 → 25.6px */
div div { font-size: 1.6em; }  /* 41px */
div div div { font-size: 1.6em; }  /* 65px */

一条看起来是”1.6 倍”的规则,嵌套几层就变成”1.6ⁿ 倍”。em 很适合组件内部、应随该组件文字缩放的间距;用于全局字号标尺则有危险,那里 rem 更稳妥。

%:两条截然不同的规则

% 是最被滥用的单位,因为含义取决于属性:

  • font-size 上,% 相对继承的字号:font-size: 150% = 父级字号的 1.5 倍(与 1.5em 行为相同)。
  • 布局属性(width、margin、padding、top/left)上,% 相对包含块——而且宽度的百分比和高度百分比不一样(高度百分比在父级没有明确高度时常无法解析)。
.child { width: 50%; }       /* 父级宽度的一半 */
.parent { font-size: 120%; } /* 祖父字号的 1.2 倍 */

所以 % 用在宽度/边距是流式布局的看家本领,用在 font-size 上实际就是 em——按你真正想表达的意思来选。

视口单位:vw、vh、dvh

视口单位跟随浏览器窗口:1vw = 视口宽度的 1%,1vh = 视口高度的 1%,vmin/vmax 是两者中较小/较大的那个。

.hero { height: 100vh; }     /* 整个窗口高度 */
.fluid { font-size: clamp(1rem, 4vw, 2.5rem); }  /* 流式字号,带钳制 */

两个实用提示:

  • 100vh 与手机。 手机上地址栏吃掉部分”视口”,所以 100vh 会超出一截被裁掉。dvh(动态视口高度)跟随可见视口,是现代解法:height: 100dvh
  • 流式字号。 vw 字号配 clamp(),字号随屏宽缩放但被钳在界内——这是几条断点 hack 行的现代替代。

ch、ex 及其余

ch 等于当前字体里 0 这个字符的宽度——最适合等宽类尺寸:<code> 块上 width: 80ch 给出以字符计的舒适行长。ex 是字母 x 的高度,很少用。其余(cmmminpt)只在打印样式表里有意义。

选单位:一张决策表

你在给什么定尺寸单位为什么
文字(font-size)rem尊重用户设置;随根缩放
边框、阴影、利落的线px任何缩放都固定清晰
组件内部、随组件文字缩放的内边距em随该组件缩放——但小心嵌套
宽度 / 流式布局%(或 flex/grid)跟随容器
整屏 hero、遮罩vw/dvh跟随可见视口
等宽行长ch”字符数”才是文本栏的正确单位

最干净的现代策略:类型用 rem、边框阴影用 px、布局用 % 或 grid/flex 轨道、em 只在自足组件内部用、任何要填满屏幕的东西用 dvh

快速参考

  • 绝对单位(pxptcmmm)固定;相对单位对父级、根或视口求值。
  • rem = 根字号——整文档标尺,尊重用户设置。文字默认。
  • em = 元素自身字号;嵌套里复利1.6ⁿ),组件内很棒,全局标尺有风险。
  • % 被过度使用:在 font-size 上是”× 继承字号”(同 em);在 width/margin 上是”× 包含块”。
  • 1vw/1vh = 视口宽/高的 1%;手机整屏用 dvh(地址栏问题)。
  • ch = 0 的宽度;等宽行长最理想。
  • 策略:rem 类型 + px 效果 + %/flex/grid 布局 + em 组件内 + dvh 整屏。

想把设计稿从 px 迁到 rem 又不想做算术,Px to Rem Converter 直接换算任意值并展示标尺。单位是每个布局网格渐变底下安静的底层——解析规则选对了,布局在每一个你从没测过的缩放档位上都站得住。