跳到主要内容
代码工具2026-10-21Begin5 分钟阅读

CSS 单位分界:px、rem、em 各管什么,换算怎么不出错

font-size: 16px 和 font-size: 1rem 在大多数用户的浏览器里渲染出来一样大,于是「px 和 rem 随便用」的误解流传很广。实际上这两个单位回答的是不同的问题:px 问「多少个像素点」,rem 问「根字号的多少倍」——后者跟着用户的浏览器设置走,前者不。分清这三个单位「各管什么」,换算只是小学数学;分不清,换算公式背得再熟也会踩坑。懒得算的时候,px ↔ rem 换算工具 支持自定义 root 字号双向换算,pt/vw/em 的互转用 CSS 单位转换器。

三个单位的分界线

单位相对于谁变化的触发条件该用的地方
px设备像素(CSS 参考像素)不随任何字体设置缩放1px 分隔线、box-shadow 偏移、发丝线
rem根元素 <html> 的 font-size用户改浏览器默认字号、或你改了 html{font-size}字号、间距、圆角、断点——几乎所有排版
em当前元素的 font-size(继承自父级)任何祖先的字号变化行高(1.5 无单位更佳)、组件内相对间距

一句话记忆:rem 管全局一致,em 管局部成比例,px 管物理固定。

换算:公式与速查表

rem = px / root-font-size      (root 默认 16px)
px  = rem × root-font-size

root = 16 时的常用速查(这份表内置在换算工具里,带语义标注):

pxrem语义
120.75辅助文字
140.875正文(紧凑)
161root 基准
181.125小标题
241.5标题
322大标题
483Display

换算的小数处理有个细节:px→rem 常产生无限小数(如 15/16 = 0.9375),保留 3-4 位即可,浏览器不需要更多;反方向 rem→px 总是有限小数(rem × 16),保留 2 位足够。

为什么排版单位押注 rem:无障碍这条硬理由

浏览器「字体大小」设置(Chrome 设置 → 外观 → 字号)改的是默认 root font-size。视力不好的用户把它从 16 调到 20,此时:

  • 全用 rem 的站点:整体等比放大,版式不破;
  • 全用 px 的站点:用户调了个寂寞——什么都不变,或者更糟,rem 混 px 的站点只有文字变大、容器和间距不变,直接溢出破版。

这就是「哪些属性该用 rem」的判断标准:凡是应该跟着用户字号走的(字号、行高、padding、margin、width/height 的文字容器),用 rem;物理装饰(1px 线、阴影偏移)用 px。浏览器最小字号限制是另一层原因,见 FAQ。

em 的复合缩放陷阱

em 相对的是当前元素的 font-size,而当前元素的 font-size 又可能继承自父级——嵌套列表就是经典事故现场:

li { font-size: 1.2em; }  /* 每层列表放大 20%:1.2 × 1.2 × 1.2 … */

三层嵌套后字号变成 16 × 1.728 ≈ 27.6px,视觉上「越嵌越大」。同理,padding 用 em 时,同一组件在不同字号上下文里的实际间距不同——这有时是特性(比例间距),有时是 bug(对不齐)。排错技巧:DevTools 的 Computed 面板里看 font-size 的最终计算值,从根到叶逐层对账。

html { font-size: 62.5% } 派系:方便与代价

一个流行技巧把 root 调成 10px(62.5% × 16),让换算变成小数点移位:2.4rem = 24px,心算零负担。代价是放弃了浏览器默认字号的接入:不少用户设置了非默认 root(20px、24px),62.5% 一刀切回 10px,对他们的字号设置是降维打击;另有部分老浏览器把小于 12px 的 root 强制抬到最小字号,10px 基准直接失真。

折中做法是不动 root,用编辑器插件或构建期工具做换算(PostCSS px2rem 之类)——心算外包给工具,无障碍红利留给用户。

媒体查询里的 rem 陷阱

@media (min-width: 40rem) 里的 rem 相对的也是 root font-size——听起来一致,但 Safari 有个历史行为:媒体查询里的 rem 永远按 16px 算,无视你改过的 html。如果你用了 62.5% 派( root=10px),断点 40rem 在 Safari 是 640px,在其他浏览器是 400px——同一个断点跨浏览器差 240px,布局直接分叉。这是 62.5% 派的又一记暗箭,也是「断点用 px 或 vw,内容用 rem」这一流派的理由。

实现注记 / Implementer's note

站内换算工具的实现刻意保持纯函数:pxToRem(px, root) 输出保留 4 位并去掉尾零(0.7500 → 0.75,复制出去的是干净字面量),remToPx 反向保留 2 位(像素值没有更高精度需求)。root 字号可调且下限钳在 1(有人真的用 62.5% 派,输入 10 是合法场景,输入 0 或负数则抛错而不是除零静默)。双向输入框联动但不锁死——手动改过的另一侧不会被下一个按键覆盖,这是实测写文档时被自己烦到之后改的。速查表的语义标注(辅助文字/正文/标题)来自中文 Web 排版惯例,和英文系的 type scale 命名不同,但数值重合。

FAQ

rem 在所有浏览器都支持吗?

IE9+ 即支持,2026 年讨论「支不支持」已经没有意义;真正需要留意的只剩上面说的 Safari 媒体查询 rem 行为。

Chrome 的最小字号设置会破坏 rem 布局吗?

Chrome 有 6px 硬下限、且「字号设置」对部分 UI 生效方式特殊,极端设置下 rem 文本可能被抬到比计算值大——这不是 bug,是无障碍机制在工作。布局要在这类抬升下不破版,恰好是 rem + 弹性容器的主场。

行高该用 em 还是无单位?

无单位(如 line-height: 1.5)最佳:它按每个元素自己的字号算比例并被子元素继承为「比例」,em 行高则把计算值固化后继承,子元素字号变了行高不跟——这是 line-height 继承机制的知名坑,值得单独记一条。

设计稿标注是 px,怎么整体迁到 rem?

按 root=16 逐值除即可(批量换算用工具),或构建期接 PostCSS 插件自动转换;间距体系建议顺手归整到 4/8 的倍数,不然 rem 化之后小数位会很难看。


这篇单位分界笔记整理自 ToolVault 工具匣的换算工具实现,速查表与联动行为都来自开发中的实测取舍。

补充注记

双向输入联动最初做成了硬同步(改一边另一边必被覆盖),自己写文档时连续输 1.1 1.125 被中间值打断三次后才改成「手动编辑优先」——工具开发里最有价值的测试员永远是第一个真实用户。