写微信小程序的时候,有一个单位叫 rpx。规则非常简单:不管手机屏幕多宽,整个屏幕宽度始终等于 750rpx。设计稿按 750 画,元素宽度是 375rpx,就是半个屏幕。大屏上半个屏幕,小屏上还是半个屏幕,换算全由框架处理。
Web 里没有这种"生来响应式"的单位,而AI 写 Web 样式时,默认用 px——数字直观,写出来就是那么多像素。但 px 是固定的,不随屏幕变化。桌面上 16px 的字看着正常,手机屏幕一换,该缩的不缩,该放的不放,布局就乱了。
em、rem、vw 这套组合,每一个解决的是不同场景下的响应式问题,不是同一件事的四种写法。

px:不跟任何东西走的固定值
.card {
width: 320px;
font-size: 16px;
border: 1px solid #e0e0e0;
}px 是最直接的单位——写 320px 就是 320 个 CSS 像素,跟屏幕宽度无关,跟父元素无关,跟字号设置无关。
这不是坏事。很多东西就该固定:边框厚度(1px)、圆角(4px)、分割线(1px)、图标尺寸(24px)——这些值在大屏和小屏上都应该保持一致,用 px 反而是对的。
不适合用 px 的,是那些需要随屏幕或字号变化的东西:整体布局宽度、段落字号、内外边距。用了 px,就等于把适配工作全部扔给 media query 手动处理,维护成本很高。
AI 写布局容器、字号、间距时倾向于用 px,这是最常见的翻车点。想改掉这个习惯,一条指令就够:
字号和间距用 rem,响应式容器宽度用 vw 或百分比,固定装饰类尺寸(border、border-radius、icon 大小)用 px。
em:跟父元素字号走,嵌套会叠加
.parent {
font-size: 16px;
}
.child {
font-size: 1.5em; /* 16 × 1.5 = 24px */
padding: 1em; /* 24 × 1 = 24px */
}em 是相对值——1em 等于当前元素的字号。当前元素没有显式设字号,就往父元素找,一层一层往上,直到找到为止。
padding、margin 用 em 时,计算基准是当前元素自己的字号,不是父元素的。padding: 1em 的意思是:内边距等于这个元素的字号大小。这没什么问题——按钮的内边距跟着按钮字号走,字号变了内边距也跟着变,天然自适应。
问题出在嵌套。
.outer {
font-size: 1.2em; /* 假设继承了 16px:16 × 1.2 = 19.2px */
}
.inner {
font-size: 1.2em; /* 19.2 × 1.2 = 23.04px */
}
.innermost {
font-size: 1.2em; /* 23.04 × 1.2 = 27.65px */
}每嵌套一层,字号就乘一次。嵌深了,字号会越滚越大,和写的时候想的完全不一样。

em 最适合的场景是组件内部、跟字号强相关的间距——比如按钮的左右 padding 用 em,字号调大了,按钮的留白自动跟着变宽,视觉比例不变。全局字号不适合用 em,那是 rem 的活。
rem:跟 html 根字号走,改一处全改
html {
font-size: 16px; /* 根字号 */
}
h2 {
font-size: 1.5rem; /* 16 × 1.5 = 24px */
}
p {
font-size: 1rem; /* 16 × 1 = 16px */
margin-bottom: 1.5rem; /* 16 × 1.5 = 24px */
}rem 全称 root em,计算基准永远是 html 元素的字号。不管嵌套多深,1rem 始终等于 html 的字号——不叠加,不漂移。
rem 的价值就在这里——整站所有用了 rem 的尺寸,只需要改一个地方:html { font-size },全部联动。浏览器默认 html 字号是 16px,如果把浏览器字号调大,基于 rem 的布局会自动跟着放大,无障碍体验更好。

再进一步,可以在响应式里直接调根字号:
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}小屏整体缩小,大屏恢复正常。改的只是一行,不用逐条 media query 覆盖每个元素。
字号和间距,默认推荐 rem。给 AI 的指令:
字号统一用 rem,根字号设 16px。间距(padding、margin)优先用 rem,只有 border 和 box-shadow 等装饰性尺寸保留 px。
vw / vh:直接跟视口走
.hero {
width: 100vw; /* 视口宽度的 100% */
height: 60vh; /* 视口高度的 60% */
}
.section-title {
font-size: 5vw; /* 视口宽度的 5% */
}1vw 等于视口宽度的 1%,1vh 等于视口高度的 1%。视口是浏览器可见区域的大小,和父元素、根字号都无关。

vw 最适合的场景:
• 全宽容器:需要撑满整个屏幕宽度, width: 100vw比width: 100%更可靠,因为 100% 是相对父元素的• Hero 区域高度: height: 60vh让 Hero 始终占视口高度的六成,不管屏幕多高• 大字号标题:大屏上想要显眼的标题, font-size: 4vw会随屏幕变宽自动放大
细小组件的内部尺寸不适合用 vw——按钮 padding、卡片 margin 用了 vw,宽屏上会过度放大,用 rem 更合适。
clamp() 是更现代的写法,设定最小值、首选值和最大值,字号在范围内线性响应:
h1 {
font-size: clamp(1.5rem, 4vw, 3rem);
/* 最小 24px,随 vw 变化,最大 48px */
}不用写 media query,字号还能平滑过渡,在响应式场景里越来越常用。给 AI 的指令:
Hero 区域和全屏容器用 vw/vh,响应式标题可以用 clamp(最小值, vw, 最大值),组件内间距用 rem。
和小程序 rpx 对比看一下
回到最开始说的 rpx。小程序的逻辑是:屏幕宽度 = 750rpx,设计稿也按 750 画,元素宽 375rpx 就是半屏,简单直接。
Web 为什么没有这种单位?两个原因。
第一,历史债。Web 比小程序早了二十年,最早的 CSS 里只有 px,响应式概念是后来才慢慢加进来的,em、rem、vw 是一步一步打补丁打出来的体系,不是一开始就设计好的。
第二,多端复杂性。Web 要处理的屏幕差异远比小程序大——从 320px 的旧手机到 4K 显示器,字号缩放、系统设置、浏览器偏好都要兼顾。rpx 的简洁是以锁定特定设备假设为代价的,Web 没有这个条件。
在 Web 里最接近 rpx 的做法,是把根字号设成 vw,全站再用 rem:
html {
font-size: calc(100vw / 37.5); /* 以 375 宽为基准,1rem ≈ 10px */
}这样 rem 就有了"跟屏幕宽成比例"的特性,用起来和 rpx 差不多是一回事。
各单位适用场景速查

CSS 单位使用场景速查表











