Appearance
rem / em / vw 响应式布局单位详解
导航目录
核心概念
在移动端做响应式布局时,em、rem、vw 都是相对单位。它们的差异在于参照物不同:字体大小、根元素或视口。
概览
| 单位 | 参照对象 | 适用场景 |
|---|---|---|
| em | 当前元素的 font-size | 组件内部跟随文字大小变化的间距 |
| rem | 根元素(html)的 font-size | 全站统一缩放的尺寸体系 |
| vw | 视口宽度(100vw = 视口宽度) | 布局宽度、栅格、间距 |
em(相对当前元素的字体大小)
em 是相对当前元素的 font-size(更准确地说,是相对"当前元素计算后的字体大小")。
基础示例
html
<div class="parent">
<div class="child">text</div>
</div>css
.parent {
font-size: 50px;
}
.child {
font-size: 1em; /* 50px */
padding: 0.5em; /* 25px */
}注意
em 容易出现嵌套叠加:多层组件都用 em 改字体大小时,最终数值可能被层层放大/缩小,导致样式失控。
css
/* 嵌套叠加示例 */
.level1 {
font-size: 2em;
} /* 2em = 32px (假设默认16px) */
.level2 {
font-size: 2em;
} /* 2em = 64px (相对于父级32px) */
.level3 {
font-size: 2em;
} /* 2em = 128px (相对于父级64px) */rem(相对根元素 html)
rem(root em)是相对根元素(html)的 font-size。
基础示例
css
html {
font-size: 100px;
}
.box {
width: 1rem; /* 100px */
padding: 0.5rem; /* 50px */
font-size: 0.16rem; /* 16px */
}核心优势
- 适合做统一缩放:只要调整
html { font-size: ... },全站使用rem的尺寸会一起变化 - 避免嵌套问题:与
em不同,rem始终相对于根元素,不受父元素影响
常见实践:移动端适配
javascript
// 根据屏幕宽度动态设置根字号
function setRem() {
const designWidth = 750; // 设计稿宽度
const baseFontSize = 100; // 1rem = 100px
const scale = document.documentElement.clientWidth / designWidth;
document.documentElement.style.fontSize = baseFontSize * scale + "px";
}
window.addEventListener("resize", setRem);
setRem();css
/* 使用 CSS clamp() 函数(现代浏览器支持) */
html {
font-size: clamp(12px, 2vw, 20px);
}vw(相对视口宽度)
vw(viewport width)是相对视口宽度,视口宽度被均分为 100 份。
计算方式
假设视口宽度是 750px:
1vw = 750px / 100 = 7.5px10vw = 75px100vw = 750px(满屏宽度)
基础示例
css
.card {
width: 50vw; /* 视口宽度的一半 */
padding: 2vw; /* 随视口宽度变化的间距 */
font-size: 4vw; /* 随视口宽度变化的字体大小 */
}优势
vw 不依赖字体大小,天然跟着屏幕宽度变化;做宽度、间距、布局比例时很顺手。
对比与选型
使用场景推荐
| 场景 | 推荐单位 | 原因 |
|---|---|---|
| 布局宽度 / 栅格 / 间距 | vw | 直接关联视口,响应式最自然 |
| 全站统一缩放的尺寸 | rem | 通过根字号统一控制 |
| 组件内部跟随文字的间距 | em | 按钮 padding 随字体变大 |
| 字体大小 | rem 或 px | 保证可读性,避免过小 |
混合使用示例
css
.component {
/* 布局宽度用 vw */
width: 90vw;
max-width: 1200px;
/* 内部间距用 rem */
padding: 1rem;
margin: 0.5rem;
/* 字体大小用 rem */
font-size: 1rem;
/* 行高用无单位数值 */
line-height: 1.5;
}常见坑与解决方案
1. 移动端视口配置
问题:没有正确的 viewport 配置,vw 的计算可能与你预期不一致。
解决方案:
html
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>2. em 的嵌套叠加
问题:组件库/多层嵌套时,em 的值会被层层放大/缩小。
解决方案:
- 组件库推荐使用
rem或px - 如需使用
em,确保组件内部有明确的字体大小基准
3. 字体大小过小
问题:使用 vw 设置字体时,在小屏幕上可能过小。
解决方案:
css
/* 使用 clamp() 限制字体大小范围 */
.text {
font-size: clamp(14px, 2vw, 18px);
}
/* 或使用媒体查询 */
.text {
font-size: 2vw;
}
@media (max-width: 375px) {
.text {
font-size: 14px;
}
}4. 1px 边框问题
问题:在高清屏上,1px 边框可能显示过粗。
解决方案:
css
/* 使用 transform: scale() */
.border-1px {
position: relative;
}
.border-1px::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1px;
background: #ccc;
transform: scaleY(0.5);
transform-origin: 0 0;
}最佳实践总结
- 移动端适配首选
rem:通过动态设置根字号实现等比缩放 - 流式布局用
vw:适合不需要严格还原设计稿的场景 - 组件内部用
em:让间距随字体大小自然变化 - 限制字体大小范围:使用
clamp()或媒体查询防止字体过小 - 设置最大宽度:使用
max-width防止在大屏幕上内容过宽
css
/* 完整的移动端适配方案 */
html {
font-size: calc(100vw / 7.5); /* 以 750px 设计稿为基准,1rem = 100px */
}
body {
max-width: 750px;
margin: 0 auto;
font-size: 0.28rem; /* 28px */
}
.container {
width: 100%;
padding: 0.3rem;
}