在 CSS 的世界里,精确控制元素尺寸是构建现代、响应式网页的基石。除了我们熟知的像素 (
px),相对长度单位提供了更具灵活性和可维护性的方案。本文将深入探讨三种最常用的相对单位:vh/vw、em和rem,帮助你彻底理解它们并应用于实际项目。
1 引言
绝对单位(如 px)是固定的,一个 100px 宽的元素在任何设备上都是 100px。而相对单位则不同,它们的值是相对于另一个参考值(如视口尺寸、父元素或根元素的字体大小)来计算的。这种特性使得它们天生适配各种屏幕尺寸和设备,成为响应式设计的首选。
2 vh 和 vw:视口比例单位
2.1 概念
vh 和 vw 是相对于浏览器视口(Viewport) 尺寸的单位。
- 1vh = 视口高度的 1%
- 1vw = 视口宽度的 1%
例如,一个 50vw 宽的元素,其宽度将始终是视口宽度的一半。
2.2 特点
- 直接响应视口:尺寸随用户调整浏览器窗口大小而立即变化,响应非常直接。
- 百分比替代:在某些场景下比使用百分比 (
%) 更简单,因为它不需要依赖父元素的尺寸。 - 计算简单:
100vh就是整个屏幕的高度,100vw就是整个屏幕的宽度。
2.3 代码示例
<div class="hero-banner">
<h1>欢迎来到我的网站</h1>
</div>
<div class="sidebar">侧边栏</div>
/* 创建一个占满整个屏幕高度的区域 */
.hero-banner {
height: 100vh; /* 高度为视口的100% */
width: 100vw; /* 宽度为视口的100% */
background-color: lightblue;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
/* 创建一个始终占视口宽度20%的侧边栏 */
.sidebar {
width: 20vw;
height: 100%;
background-color: #f1f1f1;
position: fixed;
top: 0;
left: 0;
}
2.4 场景
- **全屏区块:快速实现一个占满整个屏幕的区域。
- 弹窗或蒙层:创建覆盖整个视口的模态框或背景遮罩。
- 保持纵横比的元素:结合
padding的巧妙用法(如padding-top: 56.25%用于 16:9 视频)来实现。 - 字体大小:使用
vw设置标题字体,使其随视口宽度缩放,创造出动态的排版效果(需谨慎使用,可结合clamp()函数避免过大或过小)。
3 em:基于上下文的相对单位
3.1 概念
em 是一个相对于当前元素的字体大小(font-size)的单位。
- 如果当前元素没有设置字体大小,则它会继承父元素的字体大小,并以此作为计算基准。
- 1em = 当前元素的
font-size值。 - 当用于设置
width,height,margin,padding等非字体属性时,其计算值同样基于当前元素的font-size。
核心要点:
em的参考基准是“当前元素的字体大小”,而不是父元素的字体大小。只是当自身未设置时,这个“当前字体大小”恰好等于父级的。
3.2 特点
- 级联效应:在嵌套结构中,如果每一层都使用
em定义字体大小,那么每一层的1em值都可能不同,变化会层层叠加,可能导致意想不到的放大或缩小。 - 高度上下文相关:非常适合用于控制与文本排版紧密相关的组件内部间距和大小。
3.3 代码示例
<article class="blog-post">
<h2>这是一个标题</h2>
<p>这是一段段落内容,里面有一个 <span>突出显示</span> 的文字。</p>
<button>阅读更多</button>
</article>
.blog-post {
font-size: 18px; /* 为组件设置基础上下文 */
padding: 1.5em; /* padding = 1.5 * 18px = 27px */
}
.blog-post h2 {
font-size: 1.5em; /* 字体大小 = 1.5 * 18px = 27px */
margin-bottom: 0.5em; /* margin-bottom = 0.5 * 27px = 13.5px */
}
.blog-post p {
font-size: 1em; /* 字体大小 = 1 * 18px = 18px */
line-height: 1.6em; /* line-height = 1.6 * 18px = 28.8px */
}
.blog-post span {
font-size: 0.9em; /* 字体大小 = 0.9 * 18px = 16.2px */
}
.blog-post button {
padding: 0.75em 1.5em; /* 上下:0.75*18px=13.5px, 左右:1.5*18px=27px */
font-size: 0.9em;
}
3.4 场景
- 组件化开发:在单个组件(如卡片、弹窗)内部,使用
em来设置内边距、外边距、元素大小等,确保组件内所有尺寸与组件的基准字体大小成比例。更改组件的字体大小,其内部布局会自动按比例调整。 - 按钮和表单元素:用
em设置padding,可以让按钮的内边距随其字体大小自适应变化。
4 rem:基于根元素的相对单位
4.1 概念
rem (Root EM) 是相对于根元素(<html>) 的字体大小(font-size)的单位。
- 1rem = 根元素 (
html) 的font-size值。 - 无论元素嵌套多深,
1rem的值在整个页面中都是固定的(除非根元素的字体大小改变)。
4.2 特点
- 一致性:避免了
em的级联问题,所有基于rem的尺寸都参考同一个值,易于预测和维护。 - 易于控制和缩放:只需改变根元素的
font-size,整个页面的布局和元素大小都会按比例缩放,这是实现移动端适配的核心原理。
4.3 代码示例
一种常见的移动端适配技巧是通过媒体查询动态改变 html 的 font-size。
<header>
<h1>网站标题</h1>
<nav>...</nav>
</header>
<main>
<section class="card">这是一张卡片</section>
</main>
/* 设置根元素基准值(常用设计稿宽度为750px,此时1rem=100px,方便计算) */
html {
font-size: 100px;
}
/* 实际书写时,将设计稿上的尺寸除以100,得到rem值 */
body {
font-size: 0.16rem; /* 相当于 16px */
}
header {
height: 1rem; /* 相当于 100px */
padding: 0.2rem; /* 相当于 20px */
}
h1 {
font-size: 0.36rem; /* 相当于 36px */
}
.card {
width: 3.45rem; /* 相当于 345px */
margin: 0.1rem auto;
padding: 0.2rem;
border-radius: 0.1rem;
}
/* 媒体查询,在不同屏幕宽度下调整根字体大小,实现适配 */
@media screen and (max-width: 480px) {
html {
font-size: 50px; /* 小屏幕上,基准值变小,所有rem尺寸等比例缩小 */
}
}
/* 更优雅的做法是使用CSS变量和JS动态计算根字体大小 */
4.4 场景
- 全局布局和间距:用于设置容器宽度、内外边距、定位偏移等,保证整个布局的协调和可缩放性。
- 移动端适配:这是
rem最核心的应用。通过 JS 或媒体查询根据屏幕宽度动态计算并设置html的font-size,页面所有使用rem的元素都会自动等比缩放,完美适配不同尺寸的手机屏幕。 - 可访问性:用户如果调整了浏览器的默认字体大小,使用
rem的元素会尊重用户的设置而缩放,而使用px的则不会。
5 总结与对比
| 特性 | vh / vw | em | rem |
|---|---|---|---|
| 参考基准 | 视口(Viewport)的尺寸 | 当前元素的 font-size | 根元素(<html>) 的 font-size |
| 级联性 | 无 | 有(受自身和父级字体影响) | 无(全局统一) |
| 主要应用场景 | 全屏布局、视口比例元素 | 组件内部、与文字相关的间距 | 全局布局、移动端适配、可访问性 |
| ** predictability** | 高 | 中等(在复杂嵌套中需小心) | 高 |