响应式三巨头:rem / vw / em 深度对比,移动端到底该选谁?
移动端适配这件事,选对单位就赢了一半。但 rem、vw、em 三个"亲戚"长得像,脾气却完全不同。选错了,要么计算到崩溃,要么兼容性炸裂。
一篇讲透,直接抄作业。
一、先搞懂各自的"尺子"量的是谁
| 单位 | 尺子量的是谁 | 公式 | 举个例子 |
|---|---|---|---|
| rem | 根元素 <html> 的 font-size |
1rem = html字体大小 |
html设16px → 1rem=16px |
| em | 当前元素自己(或父元素)的 font-size | 1em = 自身/父元素字体大小 |
父元素20px → 子元素1em=20px |
| vw / vh | 浏览器视口(屏幕)的宽 / 高 | 1vw = 视口宽度的1% |
屏幕375px → 1vw=3.75px |
一句话区分:rem 看"大家长",em 看"直接领导",vw/vh 看"窗外"。
二、逐个拆解:优势、坑、适用场景
rem ------ 移动端的"统治级"单位
核心优势:全局统一,一改全改。
css
css
1html { font-size: 16px; } /* 默认 */
2.container { width: 37.5rem; } /* 37.5 × 16 = 600px */
3
改一行代码,全页面等比缩放:
css
css
1@media (max-width: 375px) {
2 html { font-size: 14px; } /* 移动端变小 */
3}
4@media (min-width: 1200px) {
5 html { font-size: 20px; } /* 大屏变大 */
6}
7
行业标准做法:750px 设计稿 → 1rem = 75px
css
css
1html { font-size: calc(100vw / 7.5); }
2/* 屏幕375px → html=50px → 1rem=50px */
3/* 设计稿375px的元素 = 375/75 = 5rem */
4
✅ 兼容性极好(IE9+ 全支持)
✅ 计算简单,适合模块化开发
✅ 推荐设置
html { font-size: 62.5%; }→ 1rem=10px,心算无敌
坑: 依赖根字体设置,根字体没设好,全局翻车。
vw / vh ------ 真正的"流体"单位
核心优势:不需要任何预设,直接跟屏幕走。
css
css
1.full-banner {
2 width: 100vw;
3 height: 50vh; /* 永远占半个屏幕高度 */
4}
5.title {
6 font-size: 5vw; /* 屏幕宽375px → 字号18.75px */
7 /* 屏幕宽750px → 字号37.5px */
8}
9
字体随屏幕宽度自动缩放,零媒体查询实现流体排版。
| 扩展单位 | 含义 | 场景 |
|---|---|---|
vmin |
vw 和 vh 中较小的那个 | 横竖屏切换时取保守值 |
vmax |
vw 和 vh 中较大的那个 | 确保元素不会太小 |
坑:
- ❌ 没有最小限制------屏幕缩到200px,5vw = 10px,字看不清
- ❌ iOS Safari 地址栏收缩时 vh 会跳动
- ❌ 老浏览器(IE)不支持
解决方案:配合 clamp() 兜底
css
css
1.container {
2 width: clamp(300px, 80vw, 1200px);
3 /* 最小300px,理想80vw,最大1200px */
4}
5
em ------ 被误解最深的单位
很多人以为 em = 父元素字体大小。不完全对。
根据 W3C 标准:em 是相对于元素自身的 font-size。自身没设置,才继承父元素。
xml
html
1<div style="font-size: 20px; padding: 1em;"> <!-- padding = 20px -->
2 <div style="font-size: 0.8em; margin: 1em 0;">
3 <!-- font-size = 20×0.8 = 16px -->
4 <!-- margin = 16px(基于自身16px,不是父级20px!) -->
5 </div>
6</div>
7
真正的杀手级场景:组件内部自适应。
css
css
1.btn {
2 font-size: 1rem;
3 padding: 0.5em 1em; /* padding 随字号等比变化 */
4 border-radius: 0.3em; /* 圆角也跟着字号走 */
5}
6
字号改了,内边距、圆角自动跟随,按钮永远不失调。
坑:嵌套就是噩梦。
ini
1父 20px → 子 1.5em = 30px → 孙 1.5em = 45px → 曾孙 1.5em = 67.5px...
2
三层之后,计算直接失控。所以 em 适合组件内部,不适合全局布局。
三、终极对比表
| 维度 | rem | vw / vh | em |
|---|---|---|---|
| 基准 | html 字体 | 视口尺寸 | 自身/父元素字体 |
| 继承性 | ❌ 不继承 | ❌ 不继承 | ✅ 会继承叠加 |
| 响应式能力 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 兼容性 | IE9+ ✅ | IE 不支持 ❌ | IE8+ ✅ |
| 计算复杂度 | 简单 | 简单 | 嵌套后复杂 |
| 最佳场景 | 全局布局、间距 | 全屏、流体排版 | 组件内部、文本相关 |
四、移动端选型结论:别单选,组合拳最强
| 场景 | 推荐单位 | 原因 |
|---|---|---|
| 页面整体布局(宽高、间距) | rem | 全局可控,配合媒体查询调根字体 |
| 全屏模块 / fluid 字体 | vw / vh | 直接映射屏幕,零计算 |
| 按钮内边距 / 行高 / 圆角 | em | 随字号自适应,组件内部和谐 |
| 边框 / 阴影 / 小图标 | px | 固定尺寸不需要缩放 |
黄金组合公式:
css
css
1/* 全局:rem 控布局 */
2html { font-size: calc(100vw / 7.5); }
3.container { width: 7.5rem; padding: 0.3rem; }
4
5/* 流体:vw 控全屏 */
6.hero { height: 100vh; width: 100vw; }
7
8/* 组件:em 控内部 */
9.btn { font-size: 0.32rem; padding: 0.2em 0.6em; border-radius: 0.4em; }
10
11/* 兜底:clamp 防极端 */
12.text { font-size: clamp(14px, 4vw, 20px); }
13
五、一句话总结
rem 管全局,vw 管视口,em 管组件。移动端主力用 rem + vw 组合,em 只在组件内部登场。 三个都不是万能的,但组合起来,就是响应式的最优解。
别再纠结"选哪个"了------会组合的人,从来不做单选题。