← 字体里的隐藏开关 / unicode-range:按字符切字体 待审核 13 / 18
加餐 · unicode-range

unicode-range:按字符切字体

font-family: "Sliced" 看似一款字体,其实可以是好几张 @font-face 切片:每条 @font-faceunicode-range 声明「我只负责这段码位」,浏览器排版时逐字符查码位、挑对应的切片。于是同一个 family 名字下,Latin 字母走 Georgia、汉字走 PingFang SC——不写一行 JS,中西混排各取所需。这也是 Google Fonts 把一个 CJK 字体拆成上百个 woff2 按需下载的底层机制。

1 · unicode-range 的写法

写法 含义
U+4E2D 单个码位(「中」)
U+4E00-9FFF 区间:CJK 统一表意文字基本块
U+4?? 通配:? 代表任意十六进制位,等于 U+400-4FF
U+0-FF, U+2014 逗号分隔可列多段,一条 @font-face 管多块码位

切片静默失败:某条 @font-face 的 src(如 local("PingFang SC"))在当前系统不存在时,该切片的字符自动落到 font-family 列表的下一项,不会报错——上方 readout 实测了本机两款 local 字体是否在。

2 · fallback 本来就是逐字符的

其实不用 unicode-rangefont-family 列表的回退就不是整段切换、而是 per-character 的:浏览器对每个字符从列表第一项开始找,由第一个含有该字形的字体渲染。Georgia 只有 Latin 字形,于是「Georgia, serif」里的中文逐字穿过 Georgia 落到 serif——一行字里两款字体共存是常态,unicode-range 只是把这套机制变成可主动声明的。

真实用途:Google Fonts 的按 subset 拆包。CJK 字体动辄十几 MB,全量下载不现实——Google Fonts 返回的 CSS 里,一款中文字体(如 Noto Sans SC)被拆成上百条 @font-face,每条一个小 woff2 切片 + 一段 unicode-range(按字频聚类分块)。浏览器只在页面真的用到某切片里的字符时才发起下载,首屏往往只拉两三个百 KB 级的小文件。拉丁字体也同理:latin / latin-ext / cyrillic 各是一条切片,法语页面不会为西里尔字母多付一个字节。

3 · 相关链接

  • unicode-range · MDN——developer.mozilla.org。@font-face 描述符的精确语法:单码位 / 区间 / 通配 ?,以及「只有用到该范围字符才下载」的加载行为。
  • @font-face src 与 local() · MDN——developer.mozilla.org。src 描述符:local() 引用本机已装字体、url() 加载 webfont,以及多候选的回退顺序——本页两张切片全靠 local()。
  • Reduce web font size——web.dev。webfont 瘦身实战:subsetting 与 unicode-range 怎么配合,Google Fonts 按 subset 拆 woff2 的工程背景。