CSS教程:rem 构建响应式与可访问性的基石
编辑文章简介
rem 是 CSS 中一个相对于根元素 (<html>) 字体大小的相对长度单位。它主要用于实现弹性、可访问的网页布局和组件尺寸,是现代响应式网页设计的核心单位之一。
语法
1rem 等于 根元素 (<html>) 的 font-size 值。
核心公式:元素的实际像素值 = 元素的 rem 值 × 根元素 font-size 的像素值
/* 假设根元素 font-size 为 16px */
html {
font-size: 16px;
}
.example {
width: 2rem; /* 2 × 16px = 32px */
padding: 0.5rem; /* 0.5 × 16px = 8px */
}
对比 em:
– rem:始终相对于根元素 (<html>),是唯一的基准。
– em:相对于其自身或最近父级元素的 font-size,基准会嵌套变化,计算复杂。
.parent {
font-size: 20px;
}
.parent .child-em {
padding: 1em; /* 相对于 .parent 的 20px,结果为 20px */
}
html {
font-size: 16px;
}
.parent .child-rem {
padding: 1rem; /* 相对于根元素的 16px,结果为 16px */
}
用法
基础用法:设置根字体与使用
第一步:设置根元素 (<html>) 的 font-size
这通常在 CSS 的最开始进行,作为整个页面尺寸的基准。
/* 最常见的基础设置:使用浏览器默认(通常是16px),或显式设置为16px */
html {
font-size: 16px; /* 明确设置基准,1rem = 16px */
}
/* 或者,如果你想让 rem 的计算更方便(如 1rem = 10px),可以设置为 62.5% */
/* 浏览器默认字体大小通常是16px,16px × 62.5% = 10px */
html {
font-size: 62.5%; /* 1rem = 10px */
}
body {
font-size: 1.6rem; /* 重置 body 字体为 16px (1.6 × 10px) */
}
第二步:在样式表中使用 rem
将 rem 应用于与尺寸相关的属性,如 width、height、margin、padding、font-size 等。
.button {
font-size: 1.4rem; /* 相对于根字体大小 */
padding: 0.8rem 1.6rem; /* 内边距也会根据根字体缩放 */
border-radius: 0.4rem;
}
.card {
width: 30rem; /* 相对于根字体大小 */
margin-bottom: 2rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.1); /* 阴影也可以使用 rem */
}
第三步:通过改变根字体大小,实现整体缩放
这是 rem 强大之处。只需改变 html 的 font-size,所有使用 rem 的元素都会成比例缩放。
/* 基础样式 */
html {
font-size: 16px;
}
.box {
width: 20rem; /* 20 × 16px = 320px */
height: 10rem; /* 10 × 16px = 160px */
}
/* 当屏幕宽度小于768px时,将根字体缩小,整个页面等比缩小 */
@media (max-width: 768px) {
html {
font-size: 14px; /* 基准变小了 */
}
/* .box 现在会变为:width: 20 × 14px = 280px, height: 10 × 14px = 140px */
/* 所有使用 rem 的尺寸都自动按 14/16 的比例缩小了 */
}
进阶用法:打造响应式与可访问的设计系统
1. 结合媒体查询实现响应式断点
这是 rem 最经典的用法。通过在不同屏幕宽度下调整根 font-size,实现整个布局和组件的平滑缩放。
/* 移动优先:从小屏幕基准开始 */
html {
font-size: 14px; /* 小屏幕基准 */
}
@media (min-width: 768px) {
html {
font-size: 15px; /* 中等屏幕,整体稍微放大 */
}
}
@media (min-width: 1200px) {
html {
font-size: 16px; /* 大屏幕,使用标准大小 */
}
}
/* 你的所有组件使用 rem,无需为每个断点重写尺寸 */
.container {
max-width: 120rem; /* 在不同断点下会自动换算成不同的 px 值 */
padding: 2rem;
}
2. 与 CSS 自定义属性(变量)结合,创建灵活的主题
rem 可以和 :root(即 html)上的 CSS 变量结合,构建更可控的设计系统。
:root {
--base-font-size: 16px;
--spacing-unit: 0.5rem; /* 定义基础间距单位 */
/* 定义一套基于 rem 的间距尺度 */
--space-xs: calc(0.25 * var(--spacing-unit)); /* 0.125rem */
--space-sm: calc(0.5 * var(--spacing-unit)); /* 0.25rem */
--space-md: calc(1 * var(--spacing-unit)); /* 0.5rem */
--space-lg: calc(2 * var(--spacing-unit)); /* 1rem */
--space-xl: calc(4 * var(--spacing-unit)); /* 2rem */
}
html {
font-size: var(--base-font-size);
}
.card {
padding: var(--space-lg) var(--space-xl);
margin-bottom: var(--space-md);
}
/* 在暗黑模式下,可以调整间距尺度 */
@media (prefers-color-scheme: dark) {
:root {
--spacing-unit: 0.6rem; /* 稍微加大间距,提升可读性 */
}
}
易错点
根字体 (font-size) 设置不当或被意外覆盖
rem 依赖根字体大小。如果根字体设置错误,或被选择器权重更高的规则覆盖,整个页面尺寸都会错乱。
错误示例:
/* 在某个样式表中不小心重写了 html 的 font-size */
html {
font-size: 16px;
}
/* ... 很多代码之后 ... */
body .some-high-specificity-wrapper html {
/* 错误!选择器权重更高,覆盖了基准 */
font-size: 12px !important; /* 灾难:所有 rem 尺寸瞬间缩小 */
}
正确做法:
– 将根字体设置放在基础/重置样式表中,并使用简单的选择器(如 html {})。
– 避免在任何地方再次修改 html 的 font-size(媒体查询除外)。
– 使用 CSS 变量来管理基准值,集中控制。
在需要相对于父级字体缩放的地方误用 rem
rem 是全局基准。如果一个元素的 font-size 需要根据其直接父级容器的大小成比例变化,使用 rem 会导致它脱离父级上下文,破坏设计意图。
错误示例:
.alert-box {
font-size: 14px; /* 警告框基础字体较小 */
}
.alert-box .alert-title {
font-size: 1.5rem; /* 这会相对于根字体(如16px)计算,结果为24px */
/* 标题(24px)比容器(14px)大得多,破坏了层级关系 */
}
正确做法:
在此场景下应使用 em,使其相对于 .alert-box 的 font-size。
.alert-box {
font-size: 14px;
}
.alert-box .alert-title {
font-size: 1.5em; /* 1.5 × 14px = 21px,与父级成比例 */
}
在媒体查询中使用 rem
媒体查询(@media)中的尺寸单位(如 min-width: 768px)绝大多数情况下应使用 px。因为媒体查询的评估时机很早,如果使用 rem,而根字体又恰好通过媒体查询在改变,可能会产生循环依赖或难以预料的结果。
错误示例(可能导致问题):
html {
font-size: 16px;
}
/* 使用 rem 作为媒体查询断点 */
@media (min-width: 48rem) { /* 试图表示 768px (48×16),但此时 font-size 可能已改变? */
html {
font-size: 18px;
}
}
正确做法:
在媒体查询中使用 px。这是行业通用做法,能确保断点清晰、稳定。
@media (min-width: 768px) { /* 明确使用像素断点 */
html {
font-size: 18px;
}
}
最佳实践
建立清晰的设计基准:62.5% 技巧
将根 font-size 设置为 62.5% 是一个非常流行的技巧。它让 1rem 等于 10px(基于浏览器默认16px),极大简化了心算。
html {
font-size: 62.5%; /* 1rem = 10px */
}
body {
font-size: 1.6rem; /* 重置回 16px */
}
.button {
padding: 1.2rem 2.4rem; /* 一看就知道是 12px 24px */
font-size: 1.4rem; /* 14px */
border-radius: 0.8rem; /* 8px */
}
优点:在设计和开发之间建立了几乎 1:1 的换算关系,无需计算器。
注意:如果用户改变了浏览器的默认字体大小(如设置为20px),62.5% 会基于这个新值计算(20px × 62.5% = 12.5px),这 是可访问性特性,而非bug,意味着你的布局会适应用户偏好。
构建基于 rem 的间距系统
使用 rem 定义一套间距尺度(如 --space-sm, --space-md, --space-lg),并强制所有 margin、padding、gap 都使用这套尺度。这能显著提升UI的视觉一致性和调整效率。
:root {
/* 基础单位为 1rem */
--space-unit: 1rem;
/* 间距尺度,基于 8pt 网格系统思想(0.5rem ≈ 8px) */
--space-xxs: calc(0.25 * var(--space-unit)); /* 0.25rem */
--space-xs: calc(0.5 * var(--space-unit)); /* 0.5rem */
--space-sm: calc(0.75 * var(--space-unit)); /* 0.75rem */
--space-md: calc(1 * var(--space-unit)); /* 1rem */
--space-lg: calc(1.5 * var(--space-unit)); /* 1.5rem */
--space-xl: calc(2 * var(--space-unit)); /* 2rem */
--space-xxl: calc(3 * var(--space-unit)); /* 3rem */
}
.flow > * + * {
/* “流式”布局:所有相邻子元素之间添加垂直间距 */
margin-top: var(--space-md);
}
.card {
padding: var(--space-lg);
}
.grid {
gap: var(--space-sm);
}
优点:全局统一修改间距比例成为可能;代码更具语义;限制了随意取值。
在需要严格比例控制的组件内部使用 em
对于完全独立、需要内部严格按比例缩放的组件(如按钮组、卡片内的排版),可以在组件最外层使用 rem 定下基调,在内部使用 em。
/* 组件使用 rem 定义与外部的关系 */
.widget {
font-size: 0.875rem; /* 14px,组件基础字体 */
padding: 1rem; /* 14px,与字体无关 */
border: 1px solid #ccc;
}
/* 组件内部使用 em,确保所有内容相对于组件的 14px 成比例 */
.widget__title {
font-size: 1.5em; /* 1.5 × 14px = 21px */
margin-bottom: 0.5em; /* 0.5 × 21px = 10.5px */
}
.widget__body {
line-height: 1.6em; /* 相对于自身的 font-size */
}
优点:组件内部比例关系稳固,即使外部基准(rem)改变,或组件自身基础 font-size 调整,内部也能自动维持和谐比例。
总结与选择建议
如何选择单位?记住这个简单的决策流程:
– 大多数场景(布局、间距、组件尺寸):使用 rem。它提供全局一致性,且易于通过根字体控制实现响应式缩放。
– 需要相对于当前或父级 font-size 缩放时(如行高 line-height、组件内间距):使用 em。
– 与物理设备像素严格绑定时(如边框 border、1px 分隔线):使用 px。
– 视口相关布局(如全屏背景、大标题):可以考虑 vw/vh,但需谨慎测试可访问性。
rem 不是一个孤立的技术,它是现代 CSS 工作流中连接 可访问性、响应式设计 和 设计系统 的重要桥梁。理解并善用它,能让你写出更健壮、更易维护的样式代码。