CSS 排版与字体
排版是 Web 设计的根基
无论 UI 多么精美,内容的可读性最终还是取决于排版。字体的选择、字号的大小、行高的设置、字间距的调整——这些细节决定了用户阅读内容的舒适度。
理解 CSS 排版不只是记住几个属性,更是理解字体度量系统(baseline、x-height、cap height)和文本渲染模型。
面试定位:排版是前端面试的常考点。面试官通过 line-height 的计算、行内元素的垂直对齐、font-feature-settings 的用法等问题,问的是候选人对可读性和字体渲染的深层理解。
字体属性
font-family
.font {
/* 字体栈 */
font-family: "SF Pro Display", "Helvetica Neue", Arial, sans-serif;
/* 具名字体族 */
font-family: serif; /* Times, Georgia, serif */
font-family: sans-serif; /* Arial, Helvetica, sans */
font-family: monospace; /* Courier, monospace */
font-family: cursive; /* cursive, script */
font-family: fantasy; /* fantasy, decorative */
/* 系统字体栈 */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}
font-size
.size {
/* 绝对单位 */
font-size: 16px;
font-size: 12pt; /* 不推荐,pt 是印刷单位 */
/* 相对单位 */
font-size: 1rem; /* 相对于根元素 */
font-size: 1em; /* 相对于父元素 */
font-size: 100%; /* 相对于父元素 */
/* 视口单位 */
font-size: 2vw; /* 视口宽度的 2% */
font-size: 2vh; /* 视口高度的 2% */
font-size: 2vmin; /* 较小者 */
font-size: 2vmax; /* 较大者 */
/* clamp() 响应式字体 */
font-size: clamp(1rem, 2vw + 0.5rem, 2rem);
}
font-weight
.weight {
font-weight: normal; /* 400 */
font-weight: bold; /* 700 */
font-weight: lighter; /* 相对于父元素更轻 */
font-weight: bolder; /* 相对于父元素更重 */
/* 数值 */
font-weight: 100; /* Thin */
font-weight: 200; /* Extra Light */
font-weight: 300; /* Light */
font-weight: 400; /* Regular */
font-weight: 500; /* Medium */
font-weight: 600; /* Semi Bold */
font-weight: 700; /* Bold */
font-weight: 800; /* Extra Bold */
font-weight: 900; /* Black */
}
font-style 和 font-variant
.style {
font-style: normal; /* 默认 */
font-style: italic; /* 斜体 */
font-style: oblique; /* 倾斜(使用倾斜版本字体或算法倾斜) */
font-variant: normal;
font-variant: small-caps; /* 小型大写字母 */
}
文本属性
line-height
.line-height {
/* 推荐值:1.4 - 1.6(正文) */
line-height: 1.5; /* 无单位,最常用,相对当前 font-size */
line-height: 1.5em; /* 有单位,相对于当前元素的 font-size */
line-height: 24px; /* 固定值,不推荐 */
line-height: normal; /* 浏览器默认,约 1.2 */
}
无单位 line-height 的计算:行高 = 无单位值 × 元素的 font-size。无论 font-size 如何变化,比例关系保持。
letter-spacing 和 word-spacing
.spacing {
/* 字间距 */
letter-spacing: normal; /* 默认 */
letter-spacing: 0.05em; /* 增加字间距 */
letter-spacing: -0.05em; /* 减少字间距(用于紧凑标题) */
/* 词间距 */
word-spacing: normal; /* 默认 */
word-spacing: 0.25em; /* 增加词间距 */
}
text-align
.align {
text-align: left; /* 左对齐(默认 LTR) */
text-align: right; /* 右对齐 */
text-align: center; /* 居中 */
text-align: justify; /* 两端对齐(对英文有效,中文通常不需要) */
text-align: start; /* 文本开头对齐 */
text-align: end; /* 文本末尾对齐 */
}
text-transform
.transform {
text-transform: none;
text-transform: uppercase; /* 全大写 */
text-transform: lowercase; /* 全小写 */
text-transform: capitalize; /* 首字母大写 */
}
vertical-align 垂直对齐
基础值
.vertical {
vertical-align: baseline; /* 默认,与基线对齐 */
vertical-align: top; /* 与行盒顶部对齐 */
vertical-align: bottom; /* 与行盒底部对齐 */
vertical-align: middle; /* 与 x-height 中点对齐 */
vertical-align: text-top; /* 与父元素文本顶部对齐 */
vertical-align: text-bottom; /* 与父元素文本底部对齐 */
/* 数值 */
vertical-align: 10px; /* 正值向上 */
vertical-align: -5px; /* 负值向下 */
vertical-align: 50%; /* 相对于 line-height */
}
行内块元素的垂直对齐
/* 图片和文字垂直对齐 */
img {
vertical-align: middle; /* 让图片与同行文字居中对齐 */
}
/* 解决 inline-block 基线对齐问题 */
.inline-block {
vertical-align: top; /* 而不是默认的 baseline */
}
高级字体技术
font-feature-settings
.features {
/* 启用 OpenType 特性 */
font-feature-settings: "liga" 1; /* 连字(ligatures) */
font-feature-settings: "kern" 1; /* 字距调整(kerning) */
font-feature-settings: "smcp" 1; /* 小型大写(small caps) */
font-feature-settings: "onum" 1; /* 旧式数字(oldstyle figures) */
font-feature-settings: "tnum" 1; /* 等宽数字(tabular figures) */
/* 简写 */
font-feature-settings: "liga" 1, "kern" 1, "onum" 1;
/* 更简单的写法(现代) */
font-variant-ligatures: common-ligatures;
font-variant-numeric: oldstyle-nums tabular-nums;
}
font-display
/* 自定义字体加载策略 */
@font-face {
font-family: "MyFont";
src: url("/fonts/myfont.woff2") format("woff2");
font-display: swap; /* 加载策略 */
}
/* font-display 值 */
font-display: auto; /* 浏览器默认 */
font-display: block; /* 短暂阻塞,后交换 */
font-display: swap; /* 立即显示后备字体,后交换 */
font-display: fallback; /* 极短阻塞,后无后备 */
font-display: optional; /* 尝试使用,否则用后备 */
font-synthesis
/* 控制字体合成 */
font-synthesis: none; /* 不合成,依赖字体文件 */
font-synthesis: weight; /* 仅合成粗细 */
font-synthesis: style; /* 仅合成斜体 */
font-synthesis: weight style; /* 两者都合成 */
文本省略与截断
单行省略
.single-line {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
多行省略
.multi-line {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /* 行数 */
overflow: hidden;
}
实战:排版系统
/* 基础排版比例 */
:root {
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */
--font-size-lg: 1.125rem; /* 18px */
--font-size-xl: 1.25rem; /* 20px */
--font-size-2xl: 1.5rem; /* 24px */
--font-size-3xl: 1.875rem; /* 30px */
--line-height-tight: 1.25;
--line-height-normal: 1.5;
--line-height-relaxed: 1.625;
--letter-spacing-tight: -0.025em;
--letter-spacing-normal: 0;
--letter-spacing-wide: 0.025em;
}
/* 标题系统 */
h1, .h1 {
font-size: var(--font-size-3xl);
line-height: var(--line-height-tight);
letter-spacing: var(--letter-spacing-tight);
font-weight: 700;
}
h2, .h2 {
font-size: var(--font-size-2xl);
line-height: var(--line-height-tight);
font-weight: 600;
}
/* 正文样式 */
.body {
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
}
面试高频问题
Q: line-height 为什么推荐使用无单位数值?
回答要点:无单位 line-height 是相对于当前元素的 font-size 计算的,值会继承给子元素但保持相同的比例关系。如果使用有单位(如 em 或 px),子元素会继承计算后的绝对值,可能导致不同字号下的行高不合理。
Q: vertical-align: middle 是相对于什么对齐?
回答要点:vertical-align: middle 是让元素的垂直中点与父元素的 x-height(字母 x 的高度)的中点对齐,而不是完全居中。如果要完全居中行内元素,可以使用 flexbox(display: inline-flex; align-items: center)或者调整 line-height 使其与容器高度匹配。
Q: font-display: swap 有什么副作用?
回答要点:font-display: swap 先显示后备字体(如系统字体),等自定义字体加载完成后切换。这避免了文字闪动(FOIT),但会导致文字闪烁(FOUT)。适用于需要尽快显示内容的场景,但可能导致布局跳动(如果字体宽度差异较大)。