字体font-weight相关知识
font-weight 是前端中看似简单、但实际上涉及到 浏览器渲染机制、字体文件特性、设计一致性 的重要知识点。
我们从基础语法到渲染原理、兼容与实战优化,一步讲清楚。
# 一、基本概念:字体粗细的控制
font-weight 用来定义字体的粗细(字重)。
font-weight: normal;
font-weight: bold;
font-weight: 500;
2
3
# 二、可取值类型(两种)
| 类型 | 示例 | 说明 |
|---|---|---|
| 关键字 | normal, bold, bolder, lighter | 通用值,可被继承和计算 |
| 数值 | 100 ~ 900(100 步进) | 数值越大,字体越粗 |
# 关键字对应关系(大多数字体)
| 关键字 | 实际等价数值 |
|---|---|
normal | 400 |
bold | 700 |
bolder | 比父元素更粗(非固定) |
lighter | 比父元素更细(非固定) |
💡注意:bolder/lighter 是相对值,浏览器会根据父元素字重计算出一个近似等级。
# 三、数值映射(标准 9 级)
| 数值 | 英文名 | 中文说明 |
|---|---|---|
| 100 | Thin / Hairline | 极细体 |
| 200 | Extra Light / Ultra Light | 特细 |
| 300 | Light | 细体 |
| 400 | Normal / Regular | 常规体 |
| 500 | Medium | 中等 |
| 600 | Semi Bold / Demi Bold | 半粗 |
| 700 | Bold | 粗体 |
| 800 | Extra Bold / Ultra Bold | 特粗 |
| 900 | Black / Heavy | 黑体、超粗体 |
# 四、字体文件对字重的支持
⚠️ 重点陷阱!
并不是所有字体都支持 100~900 的全部字重。 很多字体只有少量样式,例如:
| 字体 | 可用字重 |
|---|---|
| Arial | 400, 700 |
| Microsoft YaHei 微软雅黑 | 400, 700 |
| PingFang SC | 300, 400, 500, 600, 700 |
| Roboto / Open Sans | 全系支持 |
| 思源黑体(Noto Sans CJK) | 100~900 全系列都有 |
如果设置一个字体不支持的字重,浏览器会自动选取最接近的可用字重。
# 五、font-weight 的继承规则
- 默认情况下,
font-weight是 可继承属性。 - 子元素未定义时,继承父元素的字重;
- 若设置
bolder/lighter,会根据父级的font-weight相对调整:
| 父级字重 | lighter | bolder |
|---|---|---|
| ≤ 100 | 100 | 400 |
| 200~300 | 100 | 500 |
| 400 | 300 | 700 |
| 500 | 400 | 800 |
| 600 | 400 | 900 |
| ≥ 700 | 400 | 900 |
# 六、现代字体技术:Variable Fonts(可变字体)
现代浏览器支持 可变字体(variable font),允许在一个字体文件内动态调整字重。
@font-face {
font-family: 'Inter Variable';
src: url('Inter-VariableFont_slnt,wght.ttf') format('truetype-variations');
font-weight: 100 900; /* 支持范围 */
}
.text {
font-family: 'Inter Variable';
font-weight: 537; /* 任意数值都可渲染出真实粗细 */
}
2
3
4
5
6
7
8
9
10
💡 优点:
- 一个文件支持所有字重;
- 节省加载;
- 支持动画(如字体渐变粗)。
# 七、实战:常见使用策略
# 1️⃣ 全局字重控制(项目规范)
body {
font-weight: 400;
font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
}
strong, b {
font-weight: 600;
}
2
3
4
5
6
7
# 2️⃣ 通过 Tailwind 控制(开发常用)
<p class="font-light">Light 300</p>
<p class="font-normal">Normal 400</p>
<p class="font-medium">Medium 500</p>
<p class="font-bold">Bold 700</p>
2
3
4
# 3️⃣ 特殊字体匹配(中英混排优化)
.en {
font-family: 'Roboto', sans-serif;
font-weight: 500;
}
.cn {
font-family: 'PingFang SC', 'Microsoft YaHei';
font-weight: 400;
}
2
3
4
5
6
7
8
# 八、性能与渲染注意点
| 问题 | 原因 | 优化方式 |
|---|---|---|
| 页面字体闪烁(FOIT) | 字体加载慢 | 使用 font-display: swap |
| 文字变糊 / 抖动 | 某些字重 fallback | 使用明确支持的字重 |
| 不同浏览器粗细不一致 | 渲染算法差异 | 明确声明字体族与字重 |
| 动画卡顿 | 字体重绘 | 减少字体 weight 动画或使用 variable font |
# 九、面试常问总结
font-weight用来设置字体的粗细,可以使用关键字(normal/bold)或数值(100~900)。 默认是 400,bold 对应 700。 但需要注意,不是所有字体都支持所有字重,比如微软雅黑只有 400 和 700。 如果设置了不支持的值,浏览器会自动匹配最接近的。 在现代项目中,我们会用box-sizing: border-box控制布局、用font-weight: 400/500/700区分层级; 而在可变字体(variable font)中,还可以精确控制任意字重,比如font-weight: 537。
# 十、知识图谱小结(结构化)
font-weight
├── 类型
│ ├── normal(400)
│ ├── bold(700)
│ ├── bolder/lighter(相对)
│ └── 数值100-900
├── 字体支持范围
│ ├── 部分字体仅支持400/700
│ ├── 可变字体支持100-900
├── 继承规则
│ ├── 可继承属性
│ └── bolder/lighter按父级映射
├── 性能优化
│ ├── font-display: swap
│ └── 减少 weight 动画
└── 实战
├── Tailwind font-*
├── 强调内容 bold/600
└── 混排优化(中英字体分离)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 十一、字体匹配算法
“字体匹配算法(Font Matching Algorithm)” 是浏览器渲染文字时的一个核心机制, 它决定了:你在 CSS 里写的字体名,浏览器最终实际显示的字体是什么。
# 一、为什么需要字体匹配算法?
在 CSS 里你经常会写:
font-family: "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
但并不是所有用户电脑或系统都有这些字体。 👉 所以浏览器要 从左到右 按规则查找“能显示该字符的字体”, 找不到就自动替换(fallback)到其他字体。
这整套逻辑,就是 字体匹配算法(font matching algorithm)。
# 二、浏览器字体匹配算法的执行步骤
以 Chrome 为例(其他浏览器机制大同小异)👇
# 1️⃣ 用户指定 font-family
浏览器会从 font-family 的候选列表开始,比如:
font-family: 'Roboto', 'PingFang SC', 'Helvetica', sans-serif;
会从左往右按以下顺序查找。
# 2️⃣ 字体候选查找(Font Family Matching)
浏览器在系统字体表中查找:
- 是否存在
'Roboto'? - 如果存在,是否包含所需字符(例如中文)?
如果找不到,或找到了但不支持该字符,就继续下一个。
💡 一个字体文件可能不包含全部字符集。
例如 'Roboto' 没有中文字符,它就会 fallback 到 'PingFang SC'。
# 3️⃣ 字体样式匹配(Style Matching)
确定字体族后,浏览器会寻找与当前 CSS 属性最匹配的字体样式:
| 属性 | 匹配方向 |
|---|---|
font-style | normal / italic / oblique |
font-weight | 100 ~ 900 |
font-stretch | condensed / expanded |
font-variant | small-caps 等 |
算法会在字体文件中寻找最接近的样式:
例如你设了
font-weight: 500,但字体只提供 400 和 700, 浏览器就会选择更接近的那个(通常是 400)。
# 4️⃣ 字符级别匹配(Glyph Fallback)
如果字体支持部分字符,例如英文字母 ✅、中文 ❌, 浏览器会对“缺失字符”进行逐字符匹配:
每个字符都会被查找一遍,找到一个能渲染该字形(glyph)的字体。
这就是为什么你经常在英文 + 中文混排时发现“字体风格不一致”, 因为不同字符来自不同字体文件。
# 5️⃣ 最终回退到通用字体族(Generic Families)
如果上面的所有字体都找不到,浏览器就使用 通用字体族:
| 通用族 | 含义 |
|---|---|
serif | 有衬线字体(宋体、Times) |
sans-serif | 无衬线字体(黑体、Arial) |
monospace | 等宽字体(Courier) |
cursive | 草书风格 |
fantasy | 装饰性字体 |
system-ui | 系统默认 UI 字体(如 SF Pro Text) |
# 三、简化模型总结(匹配逻辑图)
font-family
├── 第 1 层:用户声明的字体族列表
│ ├── 查找字体是否存在
│ ├── 查找是否支持字符
│ └── 若缺失则继续下一个
├── 第 2 层:字体样式匹配
│ ├── 匹配 font-weight
│ ├── 匹配 font-style
│ └── 匹配 font-stretch
├── 第 3 层:逐字符匹配(Glyph fallback)
└── 第 4 层:通用字体族 fallback(sans-serif 等)
2
3
4
5
6
7
8
9
10
11
# 四、实际应用中的问题与优化
| 问题 | 原因 | 优化建议 |
|---|---|---|
| 中文字体显示不统一 | fallback 字体不同 | 明确声明中英文字体,如 "PingFang SC", "Microsoft YaHei", Arial |
| 英文字母比中文细或偏移 | 字重差异 | 为中英文设置不同 font-family |
| 英文字体 fallback 到宋体 | 缺少英文字体声明 | 添加英文字体如 "Helvetica", "Arial" |
| 页面闪烁(FOIT/FOUT) | 字体加载慢 | 使用 font-display: swap |
# 五、现代浏览器的扩展机制
# ✅ 1. Local Font 优先级
如果字体名和系统内置字体重名(如 "Arial"),
浏览器会优先使用 本地版本(local)。
可以通过 @font-face 明确声明加载策略:
@font-face {
font-family: 'MyFont';
src: local('Arial'), url('MyFont.woff2') format('woff2');
}
2
3
4
# ✅ 2. 字体合并(Font Fallback Chain)
浏览器内部会自动维护一条 fallback 链,比如:
'Roboto'→'Noto Sans'→'PingFang SC'→'sans-serif'
因此,有时即使没写 PingFang SC,Chrome 仍能正常显示中文。
# ✅ 3. 字体缓存与预加载
为防止字体闪烁(FOIT),可用:
font-display: swap;
或预加载字体:
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
# 六、面试答题总结模板
浏览器的字体匹配算法是从开发者声明的
font-family列表开始, 按顺序查找系统中存在且支持当前字符的字体文件。 找到字体后,会根据font-weight、font-style等属性选择最接近的样式; 如果该字体不支持某些字符,会进行逐字符 fallback; 最后再回退到通用字体族(如 sans-serif)。 在实际项目中,我们会通过明确的字体链、font-display、和中英文分组优化渲染一致性。