写 CSS 时最容易被忽视、也最容易埋坑的,就是"长度单位选哪个"。很多人凭感觉写,桌面端看着没问题,一到移动端就错位、字体忽大忽小,最后靠一堆媒体查询硬补。
问题的根源在于:不同单位的参照物不一样。px 是设备像素相关,em 参照父元素字体,rem 参照根元素字体,vw/vh 参照视口。搞清楚"每个单位相对谁计算",选型就是水到渠成的事。
这篇文章按参照物把常见单位分成四类,讲清原理、坑点和适用场景,最后给出一套可以直接落地的选型方案。
一、绝对单位:px
px 是最常见的绝对单位。它名义上是"CSS 像素",逻辑上不随用户缩放而改变参照,1px 始终对应一个固定的 CSS 像素值。
优点:
- 直观、可控,设计稿是多少就写多少。
- 不受父元素、根元素字体影响,不会级联放大。
缺点:
- 完全不响应视口变化,做响应式要靠媒体查询。
- 用户调整浏览器默认字号时,px 文本不会跟着变大,可访问性差。
适用:边框、图标尺寸、需要精确控制的细节,或明确不参与响应式的部分。
二、相对字体单位:em 与 rem
em:相对父元素(或自身)字体大小
em 的参照物是当前元素的 font-size;若元素自身没设字体大小,就继承父元素的。也就是说,font-size 用 em 时参照父元素,其他属性用 em 时参照自身。
.parent {
font-size: 16px;
}
.child {
font-size: 1.5em; /* 16 * 1.5 = 24px */
padding: 0.5em; /* 参照自身 24px -> 12px */
}
坑点在于会级联:
div { font-size: 1.2em; }
三层嵌套的 div 会变成 1.2³ ≈ 1.728 倍,这是 em 最常翻车的地方。
rem:相对根元素字体大小
rem 的参照物永远是根元素 <html> 的 font-size,所以不会级联,这也是它名字的含义:root em。
html { font-size: 16px; }
.title { font-size: 2rem; } /* 32px */
因为参照固定,rem 特别适合做全局缩放和移动端适配:只要改根字号,整页尺寸等比变化。
经典技巧:62.5% 根字号
把根字号设为 62.5%,即默认 16px 的 62.5% = 10px,这样 1rem = 10px,换算心算方便:
html { font-size: 62.5%; }
/* 1.4rem = 14px, 1.6rem = 16px */
但要小心:如果设置的是固定 font-size,会覆盖用户自定义的默认字号,损失可访问性。更稳妥的做法是用 clamp() 或保留百分比形式。
三、视口单位:vw、vh、vmin、vmax
视口单位相对浏览器可视区域计算:
| 单位 | 含义 |
|---|---|
1vw | 视口宽度的 1% |
1vh | 视口高度的 1% |
1vmin | vw 和 vh 中较小者 |
1vmax | vw 和 vh 中较大者 |
.hero {
width: 100vw; /* 铺满视口宽度 */
height: 100vh; /* 铺满视口高度 */
font-size: 4vw; /* 随视口宽度等比放大 */
}
vw 的滚动条坑
100vw 包含滚动条宽度,而 100% 不包含。页面出现纵向滚动条时,width: 100vw 会横向溢出,产生左右滚动。解决方法是:
/* 方案一:用 100% 代替 */
.container { width: 100%; }
/* 方案二:扣掉滚动条宽度 */
.full { width: calc(100vw - (100vw - 100%)); }
vh 的移动端地址栏坑
移动端浏览器的地址栏会随滚动收起/展开,导致视口高度动态变化,100vh 会忽高忽低。这时应使用 动态视口单位:
dvh:动态视口高度,随地址栏变化实时调整。svh:小视口高度,地址栏展开时的最小值。lvh:大视口高度,地址栏收起时的最大值。
.hero {
height: 100dvh; /* 移动端更稳定的全屏高度 */
}
四、百分比
% 的参照物取决于属性:
width/height相对包含块的宽/高。margin/padding的相对值一律参照包含块宽度,即使padding-top也是按宽度算,这是很多人不知道的冷知识。
.box {
padding-top: 56.25%; /* 相对宽度,常用于 16:9 占位 */
}
五、怎么选?一套可落地的方案
- 字体大小:优先
rem,方便统一缩放且不级联。 - 间距 / 布局尺寸:根据设计系统选
rem或px;需要跟随字体缩放的用rem,固定细节用px。 - 全屏区块高度:用
dvh(现代浏览器)或vh(兜底),配合min-height。 - 响应式字号:用
clamp()结合vw,避免字号在极端屏幕上过大或过小:
.title {
font-size: clamp(1.25rem, 3vw, 2.5rem);
}
- 避免:用
vw直接做普通文本字号(缩放过于剧烈);用em做多层嵌套尺寸(级联失控)。
一句话总结:理解每个单位的参照物,字体和缩放用 rem,全屏用 dvh/vh,响应式用 clamp + vw,精确细节用 px。
六、最后几个提醒
line-height写无单位数值(如1.5)时,是相对自身font-size计算,且能被子元素正确继承;写成带单位的值则会继承计算结果,容易出错。- 用户调整浏览器默认字号是可访问性需求,尽量用
rem尊重它,而不是一律锁死 px。 vw单位在部分旧版浏览器对滚动条处理不一致,跨端项目要实测。- 单位可以混用,但要有规则,别同一个组件里 px、rem、em 随机出现。