Skip to content

font-weight 是前端中看似简单、但实际上涉及到 浏览器渲染机制、字体文件特性、设计一致性 的重要知识点。

一、基本概念:字体粗细的控制

font-weight 用来定义字体的粗细(字重)

css
font-weight: normal;
font-weight: bold;
font-weight: 500;

二、可取值类型(两种)

类型示例说明
关键字normal, bold, bolder, lighter通用值,可被继承和计算
数值100 ~ 900(100 步进)数值越大,字体越粗

关键字对应关系(大多数字体)

关键字实际等价数值
normal400
bold700
bolder比父元素更粗(非固定)
lighter比父元素更细(非固定)

💡注意:bolder/lighter 是相对值,浏览器会根据父元素字重计算出一个近似等级。

三、数值映射(标准 9 级)

数值英文名中文说明
100Thin / Hairline极细体
200Extra Light / Ultra Light特细
300Light细体
400Normal / Regular常规体
500Medium中等
600Semi Bold / Demi Bold半粗
700Bold粗体
800Extra Bold / Ultra Bold特粗
900Black / Heavy黑体、超粗体

四、字体文件对字重的支持

⚠️ 重点陷阱!

并不是所有字体都支持 100~900 的全部字重。 很多字体只有少量样式,例如:

字体可用字重
Arial400, 700
Microsoft YaHei 微软雅黑400, 700
PingFang SC300, 400, 500, 600, 700
Roboto / Open Sans全系支持
思源黑体(Noto Sans CJK)100~900 全系列都有

如果设置一个字体不支持的字重,浏览器会自动选取最接近的可用字重

五、font-weight 的继承规则

  • 默认情况下,font-weight可继承属性
  • 子元素未定义时,继承父元素的字重;
  • 若设置 bolder / lighter,会根据父级的 font-weight 相对调整:
父级字重lighterbolder
≤ 100100400
200~300100500
400300700
500400800
600400900
≥ 700400900

六、现代字体技术:Variable Fonts(可变字体)

现代浏览器支持 可变字体(variable font),允许在一个字体文件内动态调整字重。

css
@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; /* 任意数值都可渲染出真实粗细 */
}

💡 优点:

  • 一个文件支持所有字重;
  • 节省加载;
  • 支持动画(如字体渐变粗)。

七、实战:常见使用策略

1️⃣ 全局字重控制(项目规范)

css
body {
  font-weight: 400;
  font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
}
strong, b {
  font-weight: 600;
}

2️⃣ 通过 Tailwind 控制(开发常用)

html
<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>

3️⃣ 特殊字体匹配(中英混排优化)

css
.en {
  font-family: 'Roboto', sans-serif;
  font-weight: 500;
}
.cn {
  font-family: 'PingFang SC', 'Microsoft YaHei';
  font-weight: 400;
}

八、性能与渲染注意点

问题原因优化方式
页面字体闪烁(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
     └── 混排优化(中英字体分离)

十一、字体匹配算法

字体匹配算法(Font Matching Algorithm)” 是浏览器渲染文字时的一个核心机制, 它决定了:你在 CSS 里写的字体名,浏览器最终实际显示的字体是什么。

一、为什么需要字体匹配算法?

在 CSS 里你经常会写:

css
font-family: "PingFang SC", "Microsoft YaHei", Arial, sans-serif;

但并不是所有用户电脑或系统都有这些字体。 👉 所以浏览器要 从左到右 按规则查找“能显示该字符的字体”, 找不到就自动替换(fallback)到其他字体。

这整套逻辑,就是 字体匹配算法(font matching algorithm)

二、浏览器字体匹配算法的执行步骤

以 Chrome 为例(其他浏览器机制大同小异)👇

1️⃣ 用户指定 font-family

浏览器会从 font-family 的候选列表开始,比如:

css
font-family: 'Roboto', 'PingFang SC', 'Helvetica', sans-serif;

会从左往右按以下顺序查找。

2️⃣ 字体候选查找(Font Family Matching)

浏览器在系统字体表中查找:

  • 是否存在 'Roboto'
  • 如果存在,是否包含所需字符(例如中文)?

如果找不到,或找到了但不支持该字符,就继续下一个。

💡 一个字体文件可能不包含全部字符集。 例如 'Roboto' 没有中文字符,它就会 fallback 到 'PingFang SC'

3️⃣ 字体样式匹配(Style Matching)

确定字体族后,浏览器会寻找与当前 CSS 属性最匹配的字体样式:

属性匹配方向
font-stylenormal / italic / oblique
font-weight100 ~ 900
font-stretchcondensed / expanded
font-variantsmall-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 等)

四、实际应用中的问题与优化

问题原因优化建议
中文字体显示不统一fallback 字体不同明确声明中英文字体,如 "PingFang SC", "Microsoft YaHei", Arial
英文字母比中文细或偏移字重差异为中英文设置不同 font-family
英文字体 fallback 到宋体缺少英文字体声明添加英文字体如 "Helvetica", "Arial"
页面闪烁(FOIT/FOUT)字体加载慢使用 font-display: swap

五、现代浏览器的扩展机制

✅ 1. Local Font 优先级

如果字体名和系统内置字体重名(如 "Arial"), 浏览器会优先使用 本地版本(local)

可以通过 @font-face 明确声明加载策略:

css
@font-face {
  font-family: 'MyFont';
  src: local('Arial'), url('MyFont.woff2') format('woff2');
}

✅ 2. 字体合并(Font Fallback Chain)

浏览器内部会自动维护一条 fallback 链,比如:

'Roboto''Noto Sans''PingFang SC''sans-serif'

因此,有时即使没写 PingFang SC,Chrome 仍能正常显示中文。

✅ 3. 字体缓存与预加载

为防止字体闪烁(FOIT),可用:

css
font-display: swap;

或预加载字体:

html
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

六、面试答题总结模板

浏览器的字体匹配算法是从开发者声明的 font-family 列表开始, 按顺序查找系统中存在且支持当前字符的字体文件。 找到字体后,会根据 font-weightfont-style 等属性选择最接近的样式; 如果该字体不支持某些字符,会进行逐字符 fallback; 最后再回退到通用字体族(如 sans-serif)。 在实际项目中,我们会通过明确的字体链、font-display、和中英文分组优化渲染一致性。