常用字体下载全流程:格式、授权、安装与子集化

发布时间:2026/10/31 18:18:25
常用字体下载全流程:格式、授权、安装与子集化

做设计或者做前端的人大概都经历过这个瞬间:稿子改到第三版,甲方说“字体能不能换一个更有质感的”,你打开字体列表往下拉,全是系统自带的那几款,翻来覆去就那几个面孔。于是打开搜索框敲下“常用字体下载”,页面跳出来一大堆,点进去要么是诱导装下载器的聚合站,要么下回来一个压缩包,解压以后发现里面塞了三四个来路不明的可执行文件。更麻烦的是,好不容易装上能用了,项目上线或者交付印刷的时候,法务那边一句“这个字体商用了没”就把人问住。所以“常用字体下载”这件事,表面是找文件,实际是一整套从来源判断、格式选择、安装管理到授权核对的完整动作。这篇就把我这些年攒下来的流程摊开讲清楚,从完全没接触过字体安装的新手,到需要给团队定字体规范的负责人,都能从里面挑到能直接用的部分。

1. 把“下载”这个动作拆开:你缺的往往不是文件

很多人把字体当成一张图片,觉得下下来丢进系统就完事了。实际上一套字体从产生到进入你的项目,中间横着格式、字符集、授权范围三道门槛。越过其中任何一道,后面都会返工。我在带新人的时候反复强调一句话:装字体之前先想清楚它要用在哪儿——是给设计软件里的标题用,还是要嵌进网页给几百万访客加载,还是要打包进一个客户端安装包里。这三种用法对文件格式和授权条款的要求完全不同,用错场景,文件再好看也是废的。

1.1 字体文件的四种主流容器格式与各自的边界

先把格式这层说透。同一套字形,可能以好几种后缀发布,选错了要么白占体积,要么在老设备上直接不显示。下面这张表是我放在团队文档里的速查版本,基本覆盖了日常会遇到的九成情况。

格式常见后缀技术特点主要用途注意点
TrueType.ttf二次贝塞尔曲线描述轮廓,渲染逻辑简单桌面安装、移动端内置、部分嵌入式设备兼容性最好,但精细曲线的表现力略逊
OpenType.otf三次贝塞尔曲线,支持更丰富的排印特性与超大字符集印刷排版、专业设计、多语言字库部分老版本系统或旧软件支持不完整
WOFF.woff在 OpenType/TrueType 基础上做结构压缩网页加载(兼容旧浏览器)压缩率一般,现在主要用于兜底
WOFF2.woff2采用更高压缩率的算法,体积通常再降三成左右现代浏览器网页加载需要浏览器支持,主流环境已无压力
可变字体.ttf / .woff2单个文件承载多个字重甚至多个设计轴需要多字重的网页与客户端文件偏大,但比装五六个字重文件划算

选型的逻辑其实很直白:桌面软件里用,优先 ttf 或 otf;网页里用,优先 woff2,用 woff 兜底;需要 300、400、500、700 好几个字重又不想让用户下载五个文件,就上可变字体。这里有个反直觉的点——很多人以为 otf 比 ttf 高级所以一律用 otf,但如果你要装到一台七八年前的老设备上,或者在某个只认 ttf 的嵌入式界面里跑,otf 反而可能加载失败。我自己吃过这个亏:一套标题字体只有 otf 版本,在本地机器上完美,交付到客户的展示终端上直接回退成了默认黑体,现场改都来不及。从那以后我的习惯是,凡是可能跑到非自己控制的设备上的字体,一定优先找 ttf 版本,找不到就自己转一份。

1.2 系统预装字体为什么“看着够用,用起来抓狂”

每台电脑出厂都带了一批字体,中文环境里通常有几款黑体、宋体、楷体、仿宋,英文环境里有几套衬线和无衬线。这些字体最大的价值是零成本、零授权风险、跨设备一致,做内部文档、做临时草稿、做需要发给一堆人打开的文件,它们是最稳的选择。但它们的问题也很明显。

第一个问题是字重不全。系统自带的黑体很多时候只有常规体和粗体两档,你想做个介于两者之间的中等字重,做不到,只能靠软件模拟加粗,效果就是笔画糊在一起。第二个问题是字形风格单一,做品牌视觉的时候几乎没有辨识度,满屏都是同一个面孔。第三个问题最隐蔽——跨平台不一致。同一份文件在 Windows 上打开和在 macOS 上打开,中文回退字体可能完全不同,行高、字宽、甚至标点位置都会变,你精心调的对齐到了别人电脑上就散了。

所以“常用字体下载”这件事的真实需求,往往是补上系统字体的三个缺口:补字重、补风格、补一致性。想清楚自己缺的是哪一块,再去挑字体,比漫无目的地下一堆字体包高效得多。我的做法是维护一份最小字体清单,只覆盖四类角色:正文黑体、标题黑体、正文宋体、一款有性格的展示字体,每类挑一到两款,够用很久。

1.3 一个容易被忽略的前提:你要的是桌面授权还是嵌入授权

这一节可能是全文最不“技术”、但最容易让人吃大亏的部分。字体的授权通常按使用方式切分:个人桌面使用、商业设计稿使用、嵌入到网页、嵌入到软件或App、随硬件设备分发,这几种的授权口径完全不一样。你在某个页面上看到“免费下载”,绝大多数时候只代表“可以免费下载这个文件”,不代表“可以免费商用”,更不代表“可以嵌进产品里分发”。

我遇到过的情况是,某个项目用了某款号称免费的中文字体做海报,设计阶段一切正常,等到要把它嵌进一个展示大屏的程序里时才发现,那套字体的授权明确写了只允许个人非商业使用。最后只能整套视觉重做,返工成本远超当初省下的那点授权费。

实操上我建议按这个顺序核对,四步走完基本能定性:

  1. 找原始授权声明:不要去二手转载页看别人转述的“可商用”,一定找到字库发布方自己的授权文件原文,通常在压缩包根目录的说明文档里,或者发布页面的授权条款区。
  2. 确认授权范围是否覆盖你的用法:重点看有没有“商用”“嵌入”“再分发”“修改”这几个关键词,缺哪个就说明哪个可能不被允许。
  3. 确认“修改”是否包含子集化:网页字体几乎一定要做子集化裁剪,这在技术上属于修改字形文件。有些授权明确允许,有些则要求保持文件完整,这一条经常被漏看。
  4. 留存证据:把授权页面截图、授权文件原文、下载时间一起归档到项目资料里。不是为了应付谁,而是半年后你自己也记不清当时看的是哪一版条款。

提示:任何宣称“全网最全字体包,一次下载几百款”的资源,几乎不可能把每一款的授权都核对清楚。这类包适合拿来做风格参考和试排,真要进商业项目,还是得回到单款字体去逐个确认。

2. 挑来源:几分钟内判断一个字体包靠不靠谱

搜“常用字体下载”,结果页前排往往是聚合站。这类站点不能说全都有问题,但踩雷概率确实高。我总结了一套快速筛查法,通常扫一眼页面结构就能判断个七八成,花不了两分钟,但能省掉后面清理捆绑软件、杀毒扫描、重装系统的一堆麻烦。

2.1 官方字库渠道与开源字体仓库的分工

正常来讲,字体来源就三类,各有各的适用场景。

第一类是字库发布方自己的渠道。商业字库会有正式的授权购买流程,也会有明确标注可免费商用的产品线。开源字体项目通常在代码托管平台上维护,发布页会同时给出字体文件、授权文本和版本更新记录。这两类渠道的共同特点是:发布方能被追溯,版本号清晰,授权文件随包附带。

第二类是操作系统与办公软件自带的字体。这类字体跟着系统或软件授权走,你在自己机器上用没问题,但不能把文件提取出来单独分发或者嵌到别的产品里。这一点很多人不知道,以为装在电脑上就是自己的了,实际上提取再分发属于典型的越界。

第三类是第三方聚合站。它们的价值在于省事,一次能下到很多款,适合前期风格探索和内部试排。但用之前要接受一个前提:这些站点上的文件来源不一定可追溯,授权信息往往是转述的,甚至干脆没有。我的用法是把它当“样品间”,看中了某一款,再回头去找原始出处下载正式版本。

这个分工想清楚以后,下载行为就变得有目的性了:探索阶段随便逛,落地阶段只认源头。

2.2 可疑下载页的五个典型特征

下面这几条是我这些年踩出来的经验,命中任意两条以上,我基本就直接关页面了。

第一,下载按钮不在内容区而在页面四周的广告位,或者满屏都是“立即下载”“高速下载”的彩色大按钮,点下去跳转的是另一个域名。正常的字体下载,链接通常就是一个直链文件或者一个网盘地址,不需要经过中间页。

第二,要求先装一个下载器或者客户端。字体文件本身通常几兆到几十兆,根本不需要专门的下载工具。凡是强制你装一个 exe 才能拿到 ttf 的,装的那个东西才是它真正想给你的。

第三,压缩包解开后混着可执行文件。一个正常的字体包,解压出来应该只有字体文件、授权说明、预览图这三类东西。如果里面出现了 exe、scr、bat、vbs,或者一个伪装成“字体安装器”的程序,直接整个删掉。

第四,文件体积明显不对。一款完整的中文字体,哪怕只覆盖常用字,也很难低于一两兆。如果你下到的“中文字体”只有几百KB,那大概率是裁剪过度的残缺版本,或者干脆是个空壳。反过来,一个标称“英文手写体”的文件如果有三十兆,也值得怀疑。

第五,压缩包加密并且密码写在一个txt里。这种做法本身是为了绕开平台的文件扫描,正常字体分发没有这个必要。

注意:即便从看起来正规的聚合站下载,也建议在解压前先用安全软件扫一遍,解压时留意文件列表,不要让压缩包里的东西自动执行。

2.3 拿到文件后的第一轮体检

文件到手、解压完成,别急着双击安装。先做三件事,花不了一分钟。

看文件属性里的元信息。右键查看字体属性,正常应该能看到字体名称、版本号、版权声明、厂商信息。如果这些字段全空,或者版权声明里写着一堆看不懂的乱码,说明这个文件被处理过,来源不明。

看字符覆盖范围。这一条对中文字体尤其重要。有些号称“中文字体”的文件其实只包含几百个字形,用在标题上没问题,一旦拿去做正文,立马满屏方块。后面第五节会给一个批量检查的脚本,这里先记住要有这个意识。

看是否重复。同一款字体,系统里装了两个版本(比如一个是旧版、一个是新版),在部分软件里会表现为字体列表里出现两条同名项,选错了就会莫名其妙地显示成另一副样子。我一般装之前先把手头已有的版本清掉,保持一版一用。

这三步做完,你对这个文件的底细就有了基本判断:来源是否可追溯、字符是否完整、有没有版本冲突。后面装进系统、用到项目里,心里就有底了。

3. 装上之后才是麻烦的开始:安装、隔离与缓存

字体安装这个动作本身没有技术含量,右键、安装、等几秒,完事。真正让人抓狂的是安装之后的各种“不生效”。我带过的新人里,十个有八个在装完字体后遇到过“软件里找不到”“装了但显示不对”“昨天还好好的今天变了”这三类问题。这些问题的根子,一半在安装方式,一半在缓存。

3.1 三大平台的字体目录与安装差异

不同系统放字体的位置不一样,搞清楚这个,很多问题就能自己定位。

平台用户级目录(仅当前账户可用)系统级目录(所有账户可用)生效方式
Windows用户目录下的字体文件夹系统盘的字体目录多数情况即时生效,个别软件需重启
macOS用户资源库下的 Fonts系统资源库下的 Fonts即时生效,部分应用需重启
Linux用户主目录下的 .local/share/fonts/usr/share/fonts需要手动刷新字体缓存

这里有两组概念要分清:用户级安装和系统级安装、双击预览安装和拖进目录安装。用户级安装只对当前登录账户生效,好处是不污染系统、卸载干净、多账户环境下互不干扰;系统级安装对所有账户生效,适合共用设备。日常我推荐一律用用户级,除非是公司统一配发的机器需要给所有使用者预置字体。

Linux 下有个额外步骤容易被忘掉:文件放进目录不等于系统认识它,必须刷新缓存。命令很简单,一行就够:

# 把字体文件复制到用户字体目录后,刷新字体缓存 mkdir -p ~/.local/share/fonts cp ./your-font.ttf ~/.local/share/fonts/ fc-cache -fv # 验证是否被系统识别 fc-list | grep -i "your font name"

如果不刷新缓存,字体文件躺在目录里但系统完全看不到,表现出来就是“我明明放进去了为什么软件里没有”。这个坑在容器环境和 CI 构建里尤其常见,构建脚本忘了刷新缓存,产物里的文字全是回退字体。

3.2 用项目级隔离代替全局安装

全局装字体的最大问题不是占空间,是污染。你为了 A 项目装了一款很有性格的展示字体,半年后在 B 项目的字体列表里又看到它,手一滑选中了,交付出去才发现用错了。项目多了以后,字体列表会变成一个越来越长的垃圾场,找一款常用字体要往下翻半天。

解决办法是项目级隔离:每个项目在自己的目录里放一份字体文件,通过软件或构建流程直接引用本地路径,而不是依赖系统安装。设计软件里可以把项目字体放在工程文件同级的 fonts 目录,用的时候从文件导入或者用字体管理功能临时激活;前端项目就更简单,字体文件直接进 src/assets 目录,通过 CSS 引用,跟系统装没装完全无关。

这么做有三个明显好处。第一,团队成员拉下代码或工程文件,字体自动跟着走,不会出现“你那边显示正常我这边显示不对”。第二,字体跟着项目走,项目归档时字体一起归档,两年后重新打开还能还原。第三,卸载干净,删掉项目目录就完事,系统字体列表永远清爽。

代价是每个项目的体积会变大,中文字体一份十几兆,项目多了确实占空间。我的折中做法是:中文字体做子集化后再入库(下一节详述),通常能压到几十到几百 KB;英文字体如果本身不大就直接放进去。这样既保证了可复现性,又不至于把代码库撑爆。

3.3 软件里“看不到新字体”的四类原因与处理顺序

这是被问得最多的问题。我一般按下面的顺序排查,从最简单到最麻烦,多数情况在前两步就解决了。

排查顺序可能原因判断方法处理方式
1字体文件没真正注册进系统用系统的字体查看器打开该文件,看是否显示“已安装”重新安装一次,或确认文件已放入正确目录并刷新缓存
2软件启动早于字体安装重启软件后字体出现完全退出软件再启动,不是关窗口
3软件自身字体缓存未更新其他软件能看到,只有这一个看不到清该软件的缓存目录,或找它的字体刷新选项
4字体家族名与文件名不一致列表里出现的名字和你想的不一样用字体查看器看真实的家族名,按家族名去找

第四种情况特别隐蔽。字体的“家族名”写在文件内部,和文件名可以完全无关。你下载的文件叫标题黑.ttf,装进系统后列表里显示的可能是一个英文名,或者带厂商前缀的名字。找的时候按拼音首字母或者按字母顺序翻,往往能在意想不到的位置发现它。

还有一种更少见但确实存在的情况:字体文件本身损坏或格式不完整。表现是安装过程报错,或者装上后任何软件都不显示。这种基本没救,重新下一份,如果还是不行就说明来源有问题,换一款。

Windows 上偶尔会遇到字体缓存服务卡住,表现为装了很多字体但列表里只显示一部分。处理方式是停掉字体缓存服务、清掉缓存文件、重启服务。这个操作稍微有点重,建议先试前面三步,都不行再动缓存,动之前把正在编辑的文档存好。

4. 中文字体的体积困局:从十几兆到几十 KB

英文网页字体动辄几十 KB,中文字体却经常一上来就是十几兆,这个差距第一次见的人都会愣一下。原因不复杂:常用汉字数量摆在那儿。一套覆盖国标基本集的字库有六千多个字,覆盖扩展集则要两万多字,每个字都是一组矢量轮廓数据,累加起来体积自然上去。而英文字母加符号总共才两百来个字符。差了三十倍的字数,体积差三十倍很正常。

4.1 字库为什么这么大,以及哪些部分可以砍

一套中文字体的体积主要由三块构成:字形轮廓数据、字符映射表、排印特性与提示信息。字形轮廓是主体,砍不掉;字符映射表告诉你哪个编码对应哪个字形,也基本砍不掉;可以砍的是第三块——大量高级排印特性、精细的屏幕提示指令、以及你用不到的字符。

这里的关键判断是:你的项目实际用到多少个不同的字?一个企业官网的首页文案,去重之后可能就三四百个汉字;一份产品手册可能一两千个;只有做通用内容平台或者允许用户自由输入的场景,才需要全字符集。

这个数字一旦算清楚,优化空间就出来了。全字符集十几兆的字体,裁剪到五百个常用字,体积能压到几十 KB,加载速度和全量版本完全不是一个量级。这个操作叫子集化。

4.2 子集化的完整操作链路

我用的是 Python 生态里的一套字体处理工具,命令行操作,可以写进构建脚本自动化。

# 安装工具,brotli 是生成 woff2 必需的压缩依赖 pip install fonttools brotli # 假设 chars.txt 里是项目用到的全部字符,一行或连续存放均可 # 生成网页用的 woff2 子集 pyftsubset ./source-font.ttf \ --text-file=./chars.txt \ --flavor=woff2 \ --output-file=./dist/project-font.woff2 \ --layout-features='*' \ --no-hinting \ --desubroutinize

参数一个个说清楚,不然抄过去容易出错。

--text-file指字符清单文件,这是裁剪的依据,清单里没有的字符会被丢掉。所以清单必须完整覆盖项目可能出现的所有文字,包括标点、数字、英文、以及一些容易漏的全角符号。漏掉一个字符,页面上就会出现一个方块。

--flavor=woff2指定输出格式。如果目标环境需要 ttf,把这个参数去掉,输出就是裁剪后的 ttf。

--layout-features='*'保留全部排印特性,包括连字、上下标、替代字形等。如果你的设计里没用到这些,可以只保留需要的几个特性名,体积还能再小一点。但对中文来说这部分占比不大,我通常直接全留,省得以后要加功能又得重新生成。

--no-hinting去掉屏幕微调指令。提示信息是为了让小字号在低分辨率屏幕上更清晰,在现代高分辨率屏幕上作用有限,去掉能省一部分体积。如果你的项目要在低端设备上显示小字号正文,这一条要谨慎,可以先去掉试试实际观感。

--desubroutinize针对 CFF 轮廓的字体展开子程序,能让某些环境下的渲染更稳定,代价是体积略增。这一条不是必须的,遇到渲染异常时可以加上试试。

生成完之后一定要做验证:打开产物文件,看字符数对不对、字形有没有丢、用浏览器实际渲染一遍看观感。我见过有人裁完之后忘了把数字加进清单,结果价格页面上所有数字都变成了方块,这个事故在预览阶段完全看不出来,因为预览那页没数字。

字符清单怎么来?最靠谱的做法是从项目内容里自动提取。写个小脚本扫一遍所有的页面文案、模板文件、配置文件,把所有出现的字符去重后输出成清单,构建时自动跑一遍,这样永远不会漏。

# 从一组文本文件中提取去重字符,输出到 chars.txt import pathlib chars = set() for path in pathlib.Path("./content").rglob("*"): if path.suffix in {".html", ".md", ".json", ".txt"}: chars.update(path.read_text(encoding="utf-8")) # 补上常见标点与空白,防止遗漏 chars.update(" ,。、;:?!“”‘’()《》【】—…·0123456789") pathlib.Path("./chars.txt").write_text("".join(sorted(chars)), encoding="utf-8") print(f"共 {len(chars)} 个不同字符")

跑一遍看到字符数,你对体积就有预期了。三百到八百个字符,子集化后通常在几十 KB 量级。

4.3 网页端加载策略与字体闪烁

子集化解决的是体积问题,加载策略解决的是观感问题。字体文件再小也要走网络请求,请求没回来之前,浏览器要么用回退字体先顶着(会出现字体闪烁),要么干脆不显示文字(会出现空白期)。这两种观感都不好。

标准的处理方式是在@font-face里加font-display声明,告诉浏览器在字体加载期间怎么办。

@font-face { font-family: "ProjectSans"; src: url("./fonts/project-sans-subset.woff2") format("woff2"); font-weight: 400; font-style: normal; /* 先用回退字体渲染,字体到位后替换,避免文字长时间不可见 */ font-display: swap; /* 限定该字体负责的字符范围,范围外的字符直接走回退,减少无谓下载 */ unicode-range: U+4E00-9FFF, U+0020-007E; }

swap是对正文最友好的取值,先用系统字体把内容显示出来,自定义字体加载完再换上去。代价是会有一次视觉跳变,但因为两套字体度量接近,跳变通常不明显。如果字体是用在标题上、且标题面积不大,可以考虑optional,让浏览器自己决定要不要用(网络慢的时候直接不用),彻底避免跳变。

unicode-range是个很实用的优化。它告诉浏览器“这个字体文件只管哪些字符”,范围外的字符不用下载这个文件。如果你的页面混合了中文正文和英文标题,分别用两套字体,可以给中文那套限定 CJK 范围,给英文那套限定拉丁范围,浏览器会按需加载,互不干扰。同时它也能让回退逻辑更精准——某个生僻字如果不在你的子集里,会精确地回退到系统字体,而不是整段文字都变。

提示:子集化和按需加载是一对组合拳。只做子集化不做范围声明,浏览器依然会为了一个生僻字把整个文件拉下来;只做范围声明不做子集化,文件本身还是太大。两个一起上,效果才明显。

5. 缺字与混排:真正影响成品观感的两件事

字体装好了、体积压下去了、加载策略也配了,剩下的问题往往出在细节上。这些细节在原型阶段看不出来,等到正式内容灌进去才暴露,那时候改起来就麻烦了。两件事最值得提前处理:缺字检测和中英混排。

5.1 用脚本批量体检缺字

缺字的直接表现是方块、问号、或者空白,但更麻烦的是“部分缺”——某个字在你的字体里有,只是字形被裁剪得不完整,看着别扭又说不出哪里不对。人工一个个看是不可能的,尤其是文案几千字的项目。

用一个脚本遍历字体文件的字符映射表,把不在表里的字符列出来,几分钟就能定位问题。

from fontTools.ttLib import TTFont import pathlib font = TTFont("./dist/project-font.woff2") cmap = font.getBestCmap() # 编码到字形名的映射 text = pathlib.Path("./content/all-text.txt").read_text(encoding="utf-8") missing = sorted({ch for ch in text if ord(ch) not in cmap and not ch.isspace()}) if missing: print(f"缺失 {len(missing)} 个字符:") print("".join(missing)) print("对应编码:", [hex(ord(c)) for c in missing]) else: print("字符覆盖完整")

这段代码跑完会直接告诉你缺了哪些字。常见缺失集中在几类:全角标点(比如各种引号、破折号、省略号)、数字的各种变体、货币符号、生僻人名用字、emoji 或者特殊符号。前几类补进字符清单重新生成就行,后两类要评估:如果是用户可能输入的任意内容(比如评论区),那就不该用子集字体,应该让这部分内容走系统字体回退。

这个检查我建议放进构建流程,每次生成字体后自动跑一遍,缺字直接让构建失败。听起来严格,但比上线后被用户截图挂出来要体面得多。

5.2 中英混排的字重与基线对齐

中英混排是中文项目绕不开的场景,也是观感最容易崩的地方。一行文字里中文和英文交替出现,如果两套字体没有做过匹配,会出现几个典型问题:视觉字重不一致(中文看着偏细、英文看着偏粗)、基线不齐(英文稍微上浮或下沉)、字面大小不匹配(同样的字号,英文占的高度明显比中文小)。

处理思路是配对而不是单挑。选一款中文正文黑体的时候,同时找一款风格接近的西文字体配对,判断标准有三条:

匹配维度判断方法处理建议
字重观感同字号下看中英文的笔画粗细是否协调西文字重通常需要比中文低一档,比如中文用 400、西文用 400 或 300 试起
字面高度看大写字母高度与汉字方块的比例汉字方块通常占满字身,西文只占约七成,需要靠字号微调
基线位置中英文同行混排看底部是否对齐多数现代字体的基线是一致的,老字体可能需要手动偏移

第一直觉往往是“找一款笔画粗细一样的”,实际调起来会发现西文总是显得偏粗。原因是西文的字腔(字符内部空白)更大,同样的笔画在视觉上更重。所以我一般从中文的字重往下降一档开始试,比如中文 400 配西文 300,调出来反而更协调。

字号这块有个小技巧:如果发现英文明显偏小,不要整体调字号,只给西文字体加一个font-size-adjust或者单独设一个略大的字号。CSS 里可以这样处理:

.mixed-text { font-family: "ProjectSansLatin", "ProjectSans", sans-serif; /* 优先用西文字体渲染拉丁字符,缺失时回退中文,中文里的拉丁字符也会被西文字体接管 */ }

这个写法的关键在于西文字体放在字体栈前面。浏览器会按顺序找第一个能渲染该字符的字体,拉丁字符由西文字体接管,汉字因为西文字体里没有会被跳过,落到中文那套。这样一个font-family就实现了自动分流,不用给每个元素加 span 打标签。

标点这块还有个小坑:中文标点在部分西文字体里也有对应字形,如果西文字体排在前面,中文全角标点可能被它接管,变成半角宽度,行文看起来就怪。稳妥的做法是在西文字体的unicode-range里排除掉 CJK 标点区段,让标点明确地走中文字体。

6. 我自己的字体归档与复用习惯

前面讲的都是单次操作,最后说说长期维护。做项目多了以后会发现,字体这件事的重复成本很高——同一个需求,隔几个月又要找一遍、下一遍、验一遍。我现在的做法是建一个本地字体库,按角色分类存放,每个字体一个目录,里面固定放四样东西:字体文件本体(ttf 和 woff2 各一份)、授权说明原文、来源链接的记录、以及一张自己截的预显示意图。

目录结构大致是这样:

font-library/ ├── sans-body/ 正文黑体,只放 1-2 款 │ ├── font.ttf │ ├── font-subset.woff2 │ ├── license.txt │ └── preview.png ├── sans-display/ 标题用,可以多几款 ├── serif-body/ 正文宋体 ├── mono-code/ 等宽,代码展示用 └── README.md 记录每款的授权结论与适用场景

分类逻辑按角色而不是按字体名,这是关键。按字体名分类,一年后你只记得“那款圆圆的”,翻遍目录找不到;按角色分类,任何时候需要“正文黑体”都能立刻定位到候选。每个类别控制在两三款以内,多了反而选择困难,也不利于品牌一致性。

README.md里我记三条信息:这款字体能不能商用、能不能嵌入网页、有没有已知的缺字问题。这三条是实际项目里最常被问到的,提前记下来,团队里谁需要都能直接查。踩过的坑也写进去,比如“某款字体在低版本系统上渲染异常,慎用于需要兼容旧设备的项目”,这类经验不写下来下次一定重蹈覆辙。

最后一个习惯是归档时把子集化的字体也一起存。项目做完,原始的十几兆字体和裁剪后的几十 KB 子集都留着,子集跟着项目工程走,原始文件留在字体库。这样两年后要改一个页面,不用重新走一遍子集化流程,直接用现成的产物,加两个字进去重新生成一次也就一分钟的事。

实际用下来最省时间的其实不是下载环节,而是这套归档习惯。以前每接一个新项目,光找字体、验授权、试排版就要耗掉大半天,现在大部分情况直接从库里挑,剩下的时间可以花在真正的设计判断上。字体这东西,本质上跟螺丝钉一样,重要的是在你需要的时候,立刻知道哪一颗能用、在哪、凭什么能用。