Skip to content
Yulong Ming's Homepage
Go back

Ghostty 在 macOS 上的中文渲染问题

背景

我在 macOS 上使用 Ghostty 终端时,遇到了中文渲染异常:同一段文字里有些字大、有些字小,句号等全角标点浮在文字上方。排查后发现这不是配置了某个奇怪字体,而是 Ghostty 的中文字体 fallback 机制选错了字体。

问题

Ghostty 对主字体缺少的字形做回退时,会调用 CoreText 列出支持该字符的全部字体,按字形数量降序排序,取第一个能加载的。在我的系统上排序结果前三名是:

PingFang SC 排不进前五。STHeiti 和 Arial Unicode MS 都是 90 年代的老字体,度量与现代字体差异很大。实测 STHeiti 的句号字形位于基线上方(y=+0.2),而 PingFang 的在基线下方(y=-1.5),这就是句号浮在上方的原因。

一个细节放大了问题:Ghostty 对汉字的回退走的是另一条路径(CTFontCreateForString,能正确返回 PingFang),对全角标点走的才是上述按字形数量排序的路径。一段文本实际用哪条路径,取决于这段文本第一个缺失的字符是什么。所以同一行里有时正常、有时异常,观感就是字大小不一。

这个现象在 macOS 26.5(2026 年 5 月)系统更新后集中出现,Ghostty 的 issue #12916 有同样的报告。按字形数量排序的逻辑本身是 2023 年就有的(PR #811),所以这不是 Ghostty 版本更新引入的,而是 macOS 系统更新改变了字体回退行为,与 Ghostty 的机制相互作用的结果。

解决方案

最简单的方式是显式指定中文回退字体。Ghostty 的 font-family 可以重复配置,第一行是主字体,后面的行按顺序作为回退:

font-family = Menlo
font-family = PingFang SC

显式指定的回退字体不经过上述排序,会稳定命中 PingFang。这个方案也是官方文档和社区(包括小红书上的笔记)推荐的做法。

如果主字体和回退字体之外还有个别符号想精确控制,可以再叠加 font-codepoint-map 按 Unicode 区间强制指定字体:

font-codepoint-map = U+2013-U+2030=PingFang SC
font-codepoint-map = U+3000-U+303F=PingFang SC
font-codepoint-map = U+4E00-U+9FFF=PingFang SC
font-codepoint-map = U+FF01-U+FF5E=PingFang SC

另外两个可选动作:给 Ghostty 换一个自带汉字的等宽字体作为主字体(例如更纱黑体 Sarasa Mono SC),这样汉字和标点都在主字体里,根本不触发回退;如果 /Library/Fonts 下存在 Arial Unicode.ttf 的软链(某些工具会创建),它会因为注册顺序靠前而进一步抬高 Arial Unicode MS 的地位,可以一并删掉。


Share this post:

Previous Post
Inconsistent Naming Standards of Programming Langauges for Tests, Documentations, and Benchmarks
Next Post
用 OpenWrt 默认 LuCI 界面连接 eduroam(i.e., 802.1x EAP)作为出口