第21课:字体与文本样式
文字是网页内容的核心载体。CSS 提供了两套属性体系来控制文字的呈现:字体属性(Font Properties)决定文字使用哪种字体、多大、是否加粗倾斜——即“字符长什么样”;文本样式属性(Text Properties)控制文字的排列方式、行高、缩进、装饰线——即“文字怎么排”。理解这两者的分工以及关键属性的工作原理,是实现优雅排版的基础。本节课将系统讲解 font-family 与后备字体栈、@font-face 自定义字体、line-height 的行盒机制,以及 white-space 和文本溢出处理。
1. 字体属性:控制字符的形态
1.1 font-family:字体族系与后备字体栈
font-family 指定文字的字体。它接受一个按优先级排序的字体列表,浏览器从左到右尝试,使用第一个在当前系统中可用的字体。
1 | body { |
后备字体栈的设计原则:
- 最左侧是首选字体(通常是具体品牌的字体,如
Roboto或系统字体关键字)。 - 中间是平台备选字体(如 macOS 的
-apple-system、Windows 的"Segoe UI")。 - 最右侧必须是通用字体族(Generic Family),作为最终兜底。
五个通用字体族:
| 通用族名 | 说明 | 典型代表字体 |
|---|---|---|
serif |
衬线字体:笔画末端有装饰线,适合长文阅读。 | Times New Roman、Georgia、宋体 |
sans-serif |
无衬线字体:笔画简洁无装饰,适合屏幕阅读。 | Arial、Helvetica、微软雅黑、黑体 |
monospace |
等宽字体:每个字符占据相同宽度,适合代码展示。 | Courier New、Consolas、Fira Code |
cursive |
手写体/草书:模拟手写风格。 | Comic Sans MS、Brush Script MT |
fantasy |
装饰性字体:用于标题或特殊效果。 | Impact、Papyrus |
包含空格的字体名必须用引号包裹:
1 | h1 { |
系统字体关键字(现代最佳实践):
使用 system-ui 通用关键字可直接调用操作系统默认 UI 字体,无需维护长串的后备列表。
1 | body { |
system-ui 在各平台对应的默认字体:
- Windows:Segoe UI
- macOS / iOS:San Francisco(-apple-system)
- Android:Roboto
- Linux:取决于发行版(通常是 Noto Sans 或 DejaVu Sans)
1.2 font-size:字号与单位
font-size 定义字符的大小。
常用单位对比:
| 单位 | 类型 | 说明 | 典型场景 |
|---|---|---|---|
px |
绝对单位 | 像素。固定大小,不受父元素影响。 | 需要精确控制尺寸的场景。 |
em |
相对单位 | 相对于父元素的 font-size。1em = 父元素字号。 |
组件内部的相对缩放(如按钮内文字)。 |
rem |
相对单位 | 相对于根元素(<html>)的 font-size。1rem = 根字号。 |
全局一致的相对字号,推荐用于主体文字。 |
% |
相对单位 | 相对于父元素字号的百分比。 | 与 em 等价,150% = 1.5em。 |
vw |
视口单位 | 1vw = 视口宽度的 1%。 |
响应式标题、大屏装饰文字。 |
em 的复合效应(易错点):em 是相对于**父元素计算后的 font-size**,在嵌套结构中会逐层放大或缩小,形成“复合”效果。
1 | <div style="font-size: 16px;"> |
若希望各层级保持一致,应使用 rem:
1 | <div style="font-size: 16px;"> |
推荐全局设置:
1 | html { |
1.3 font-weight:字重(粗细)
font-weight 控制文字的粗细程度。
| 关键词 | 对应数值 | 说明 |
|---|---|---|
normal |
400 |
常规粗细(默认)。 |
bold |
700 |
加粗。 |
lighter |
比父元素细 | 相对值。 |
bolder |
比父元素粗 | 相对值。 |
也可以直接使用数值(100 ~ 900,以 100 为增量):
100:Thin(极细)300:Light(细)400:Regular(常规)500:Medium(中等)600:Semi Bold(半粗)700:Bold(粗)900:Black(极粗)
前提条件:数值字重仅在字体文件包含对应粗细的字体时才会生效。如果字体仅有 400 和 700 两种粗细,则 font-weight: 500 会映射到 400 渲染。
1.4 font-style:斜体与伪斜体
| 值 | 说明 |
|---|---|
normal |
正常字体(默认)。 |
italic |
真斜体。使用字体文件中专门设计的斜体变体。 |
oblique |
伪斜体。浏览器对正常字体进行机械倾斜模拟。 |
大多数情况下,italic 和 oblique 的视觉效果相似。但当字体缺乏真斜体时,italic 也会退化为模拟倾斜。
1.5 font 简写属性
font 属性可以一次性设置多个字体相关属性,但必须遵循严格的顺序且**必填 font-size 和 font-family**。
语法顺序:
1 | font: [font-style] [font-variant] [font-weight] font-size[/line-height] font-family |
1 | p { |
注意:未显式指定的子属性会被重置为初始值。若只写 font: 16px sans-serif;,则 font-style、font-variant、font-weight 均被重置为 normal,可能意外覆盖之前的样式。
2. @font-face:加载自定义 Web 字体
@font-face 允许开发者加载服务器上的字体文件,使网页突破用户本地字体的限制,实现品牌定制的排版。
1 | @font-face { |
2.1 src 与字体格式
src 指定字体文件的 URL 和格式。推荐使用多格式、按优先级排列的策略。
| 格式 | 文件扩展名 | 说明 | 使用建议 |
|---|---|---|---|
woff2 |
.woff2 |
压缩效率最高,文件最小。所有现代浏览器均支持。 | 首选格式 |
woff |
.woff |
上一代压缩格式,浏览器支持极广。 | 第二备选 |
truetype |
.ttf |
未压缩,文件较大。 | 仅作为老浏览器后备。 |
opentype |
.otf |
功能丰富,但文件较大。 | 需要高级排版特性时使用。 |
eot |
.eot |
仅 IE 支持。 | 现代项目无需包含。 |
2.2 font-display:字体加载策略
font-display 控制自定义字体加载期间文字的渲染行为,直接影响用户体验(特别是首屏加载时)。
| 值 | 行为描述 |
|---|---|
auto |
浏览器默认策略(通常等同于 block)。 |
block |
短暂隐藏文字(约 3 秒),等待字体加载。若超时未加载,使用后备字体。不推荐——导致文字不可见。 |
swap |
立即显示后备字体,字体加载完成后平滑切换。这是推荐值——用户始终能看到文字,无“闪烁消失”期。 |
fallback |
短暂隐藏(约 100ms)。若此时间内未加载,使用后备字体。之后不再切换(即使字体加载完成)。适用于对字体要求不极端的场景。 |
optional |
与 fallback 类似,但完全依赖网络状况。若字体未能快速加载,则放弃加载并使用后备字体。适用于网络较差的移动端。 |
最佳实践:对正文内容使用 font-display: swap,确保文字始终可见;对图标字体或品牌 Logo 字体可考虑 block 或 fallback。
2.3 多字重与多风格的加载
一个字体族通常包含多个变体文件(不同粗细、不同风格),每个变体需要一个独立的 @font-face 声明,并使用相同的 font-family 名称,通过 font-weight 和 font-style 区分。
1 | @font-face { |
使用时,浏览器会自动匹配对应粗细和风格的字体文件:
1 | body { |
3. 文本样式属性:控制排列与对齐
3.1 text-align:水平对齐
| 值 | 说明 |
|---|---|
left |
左对齐(ltr 书写模式下的默认值)。 |
right |
右对齐。 |
center |
居中。 |
justify |
两端对齐(拉伸单词/字符间距使每行等宽)。 |
start |
对齐到书写模式的行首(逻辑属性,推荐)。 |
end |
对齐到书写模式的行尾(逻辑属性,推荐)。 |
1 | p { |
注意:text-align 对块级容器内的行内内容生效,不能直接用于行内元素自身来居中。
3.2 text-align-last:最后一行的对齐方式
当段落使用 text-align: justify 时,最后一行的文字往往较短,默认左对齐。text-align-last 可单独控制最后一行的对齐方式。
1 | p { |
3.3 vertical-align:垂直对齐
vertical-align 控制行内元素或表格单元格在垂直方向上的对齐方式。注意:它不能直接用于块级元素来实现垂直居中。
常用值(行内场景):
| 值 | 说明 |
|---|---|
baseline |
默认值。元素基线对齐父元素基线。 |
top |
元素顶部对齐行盒顶部。 |
middle |
元素垂直中点对齐父元素基线 + x-height 的一半。 |
bottom |
元素底部对齐行盒底部。 |
sub |
下标对齐。 |
super |
上标对齐。 |
数值(px/em) |
正值上升,负值下降。相对于基线偏移。 |
常见场景:消除图片底部的空白间隙。
1 | <div style="border: 1px solid #ccc;"> |
图片默认按基线对齐,基线下方会留出空隙(为字体下伸部预留的空间)。解决方案:
1 | img { |
4. line-height:行高与行盒
line-height 是排版中最核心的属性之一。它定义了一行文字的最小高度(更准确地说,是行盒的高度),直接影响文字的可读性和垂直间距。
4.1 五种取值类型
| 取值 | 示例 | 计算方式 | 推荐度 |
|---|---|---|---|
normal |
line-height: normal; |
浏览器默认值(通常约 1.2,取决于字体和浏览器)。 |
不推荐(不可控)。 |
| 纯数值 | line-height: 1.5; |
元素自身 font-size × 数值。子元素继承此数值(非计算值)。 |
最推荐。 |
| 长度值 | line-height: 24px; |
固定像素值。 | 不推荐(不同字号会冲突)。 |
| 百分比 | line-height: 150%; |
相对于父元素的 font-size 计算后,将计算值继承给子元素。 |
不推荐(易导致子元素行高异常)。 |
em |
line-height: 1.5em; |
相对于父元素的 font-size,行为与百分比相同。 |
不推荐(同百分比)。 |
4.2 纯数值为何最优:继承行为的差异
这是 line-height 最经典的知识点。
1 | <div style="font-size: 20px; line-height: 1.5;"> |
line-height 值 |
父元素行高 | 子元素继承到的是 | 子元素实际行高 | 效果 |
|---|---|---|---|---|
1.5(纯数值) |
20 × 1.5 = 30px |
数值 1.5 |
40 × 1.5 = 60px |
✅ 子元素自适应 |
150% |
20 × 150% = 30px |
计算值 30px |
30px |
❌ 子元素行高太小,文字重叠 |
1.5em |
20 × 1.5 = 30px |
计算值 30px |
30px |
❌ 同百分比 |
结论:始终使用无单位的纯数值(如 1.5、1.6)设置 line-height。子元素会继承这个数值并根据自己的字号重新计算,保证行高始终与字号成比例。
4.3 line-height 的垂直居中原理
单行文字在容器内垂直居中,常见做法是将 line-height 设置为容器高度。
1 | .button { |
原理:文字在行盒内始终垂直居中。当行盒高度等于容器高度时,文字自然居中。此方法仅对单行文字可靠,多行文字需使用 Flexbox。
5. white-space 与空白处理
white-space 控制元素内空白字符(空格、换行符、制表符)的处理方式。它是 white-space-collapse 和 text-wrap 两个属性的简写。
| 值 | 空白折叠 | 自动换行 | 等效于(新语法) | 典型场景 |
|---|---|---|---|---|
normal |
折叠 | 换行 | white-space-collapse: collapse; text-wrap: wrap; |
默认行为。 |
nowrap |
折叠 | 不换行 | 文本强制不换行。 | 表格表头不换行、水平导航栏。 |
pre |
保留 | 不换行 | 行为同 <pre> 标签。 |
展示代码块、ASCII 艺术。 |
pre-wrap |
保留 | 换行 | 保留空格和换行,但允许自动换行。 | 用户输入的多行文本展示。 |
pre-line |
折叠 | 换行 | 折叠连续空格,但保留显式换行符。 | 保留诗歌或地址的换行格式。 |
break-spaces |
保留 | 换行 | 与 pre-wrap 类似,但允许在保留的空格内断行。 |
超长连续空格也能换行。 |
1 | .code-block { |
6. word-break 与 overflow-wrap:断词与溢出控制
当文本内容超出容器宽度时,这两个属性控制如何断行。
6.1 overflow-wrap
控制当一个单词过长无法放入一行时,是否在单词内部强制断行。
| 值 | 说明 |
|---|---|
normal |
默认。仅在半角空格或连字符处断行。过长的单词会溢出容器。 |
break-word |
若整个单词都放不下,则在单词内部任意字符处断行。优先尝试不破坏单词,实在放不下才强制断开。 |
anywhere |
与 break-word 类似,但断行更积极——在计算最小内容尺寸时也允许断词。 |
6.2 word-break
控制单词内部的断行规则,对所有文本生效(不仅限于溢出容器的情况)。
| 值 | 说明 |
|---|---|
normal |
默认。根据语言规则在合适位置断行(CJK 文本可在任意字符间断行)。 |
break-all |
任意字符之间都可断行。即使是英文单词,也可在任意字母间断开。 |
keep-all |
尽量不断词。CJK 文本不会在字符间随意断行,仅在空格或连字符处断行。英文单词内部不断行。 |
6.3 文本溢出省略号
单行文本溢出时显示省略号(...)是极常见的 UI 需求,需要三个属性协同作用:
1 | .ellipsis { |
多行文本溢出省略(兼容性稍差):
1 | .line-clamp-3 { |
课后练习
一、概念自测(选择题 / 填空题)
(单选) 关于
line-height的取值,以下哪个是最推荐的做法?
A.line-height: 24px;
B.line-height: 150%;
C.line-height: 1.5;
D.line-height: 1.5em;(单选) 关于
@font-face中的font-display属性,以下哪个值可以确保文字在字体加载期间始终可见,并在字体加载完成后平滑切换?
A.block
B.swap
C.fallback
D.auto(填空) 要实现单行文本溢出时显示省略号,需要同时设置三个属性:
white-space: nowrap、overflow: hidden和______。(多选) 以下哪些 CSS 属性可以用于消除
<img>底部与父容器之间的空白间隙?
A.display: block
B.vertical-align: middle
C.line-height: 0
D.float: left
二、AI 编程任务:编写面向 AI 的提示词
场景:你需要为一个新闻阅读应用设计正文排版样式。要求如下:
- 使用自定义字体
"Noto Serif SC"(一种中文衬线字体),通过@font-face加载woff2格式,并设置font-display: swap。 - 全局根字号 18px,正文使用
1rem。 - 正文
line-height设置为1.8,段落之间间距1.2em。 - 标题使用 2 倍根字号,加粗 700,
line-height为1.3。 - 代码块使用等宽字体,背景色
#f5f5f5,white-space: pre-wrap保留格式但允许换行。 - 链接文字颜色为
#0066cc,并在悬停时添加下划线。 - 文章卡片中的摘要文字限制显示 2 行,溢出显示省略号。
任务要求:请写出一段完整的中文提示词,发送给 AI,使其生成完整的 HTML 和 CSS 排版代码。提示词中应明确指定字体加载策略、字号和行高的单位选择理由、以及多行省略的技术方案。
三、面试真题与参考答案
题目(京东前端面试题):
请详细解释
line-height取值为纯数值(如1.5)、百分比(如150%)、em单位(如1.5em)时,在继承行为上有何差异?请用具体代码示例说明哪种方式是最佳实践,并解释原因。
参考答案:
1. 继承行为的核心差异:
- 纯数值(如
line-height: 1.5):子元素继承的是这个数值本身(1.5),然后乘以子元素自己的font-size得到实际行高。每个元素的行高与其自身字号成比例。 - 百分比(如
line-height: 150%):先基于父元素的font-size计算出一个具体的像素值,子元素继承的是这个计算后的固定值。子元素无论字号多大,都使用这个固定的行高。 em单位(如line-height: 1.5em):行为与百分比完全一致——先基于父元素字号计算为像素值,再将固定值传给子元素。
2. 代码示例:
1 | .parent { font-size: 20px; line-height: 1.5; } |
3. 最佳实践与原因:
始终使用无单位的纯数值。原因在于:
- 行高与字号保持恒定比例,任何嵌套深度的元素都能根据自身字号正确计算。
- 避免因子元素字号变化导致的文字重叠或间距过大的问题。
- 维护方便——修改根字号时,全局行高比例自动适配,无需逐一调整。
课后练习答案
一、概念自测答案
C
- 解析:纯数值
1.5在继承时保留数值而非计算值,子元素根据自身字号重新计算,是最灵活、最不易出错的做法。
- 解析:纯数值
B
- 解析:
swap策略立即显示后备字体,加载完成后平滑切换,用户始终能看到文字。
- 解析:
text-overflow: ellipsis- 解析:这三个属性必须同时设置才能实现单行文本溢出省略号效果。
A、B、C、D
- 解析:
display: block将图片变为块级,消除行内基线空隙;vertical-align: middle/top改变基线对齐方式;line-height: 0消除行盒高度;float使图片脱离正常流。均可消除底部空白间隙。
- 解析:
二、AI 编程任务参考答案(提示词示例)
示例提示词:
“请为一个新闻阅读应用生成完整的排版样式(HTML + CSS)。要求:
- 使用
@font-face加载自定义字体Noto Serif SC,格式woff2,设置font-display: swap。<html>根字号设为18px,正文字体使用1rem。- 正文
line-height: 1.8,段落p的margin-bottom: 1.2em。- 标题
h1字号2rem,font-weight: 700,line-height: 1.3。- 代码块
<pre><code>使用等宽字体族('Fira Code', 'Consolas', monospace),背景#f5f5f5,white-space: pre-wrap,内边距16px,圆角8px。- 链接
a颜色#0066cc,无下划线;悬停时显示下划线。- 文章摘要卡片
.summary使用多行截断(-webkit-line-clamp: 2)并显示省略号。- 请解释为何
line-height使用纯数值而非百分比。直接输出完整 HTML 文件。”