system-ui
Twitter的默认字体栈是
font-family: system-ui, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif;
这里别的都好说,问题就出在system-ui这个。
system-ui这个generic font的设计思路很美好:自动调用系统字体,给用户最原生的体验。这个思路用在移动平台上、甚至Mac OS都没有大问题,但是在Windows上问题就很多。
Windows简中默认的字体是微软雅黑,英文则是Segoe UI。当然,Segoe UI是没有CJK字符的,所以会fallback到其他字体。
微软雅黑最大的问题是中文字符还算不错,但是英文和假名都巨丑无比。所以,一旦调用了雅黑来显示日文、英文内容,立刻变得不堪入目。
对比:

所以,一旦system-ui导致调用了雅黑来显示非中文内容,效果立刻变得很差。
由于system-ui的这个问题,有许多主流网站已经刻意将system-ui从其字体栈中删除,例如GitHub、Bootstrap等等。不知道为什么Twitter目前还没有跟进(而且没记错的话,Twitter是换了新版界面之后才专门加上了system-ui)。这里有个CSSWG的相关讨论(发帖人是Chrome/Google团队的CJK字体专家Koji Ishii)。
Chrome对于system-ui的处理
不过既然标题专门提到了“Chrome”,就知道这事情没有这么简单。
确实,system-ui的behavior在Chrome和Firefox是不一致的。其核心区别在于,如何处理lang参数。
很久以前在S1发过一贴专门讲不同浏览器不同语言的fallback机制(待更新),不过这里不展开。具体到这个问题,就是Firefox面对system-ui,仍然会根据语言来选择在选项里设置的字体,而Chrome会原封不动的直接套用系统默认字体——对于简体中文Win来说,就是微软雅黑。
回到Twitter上的话,Twitter其实有个很优秀的功能就是对于每条tweet会自动分析语言,然后给那个div套上lang='xx'的选项。所以,大部分日文推是已经加了lang=ja了的(如果没加这个问题会变得更复杂)。对于Firefox,面对system-ui,看到lang=ja他会先选择你设置的日文默认无衬线字体——没记错的话默认是Meiryo——显示效果就比较美观。而Chrome里则会无脑显示为微软雅黑。
用这个HTML可以很快速地对比两者。
可以看到,对于指定了“Segoe UI”的场合,由于Segoe UI无法显示CJK字符,会fallback到其他字体。这里,无论是Firefox还是Chrome都会根据lang来选择合适的fallback字体(ja=Meiryo、zh-cn=雅黑。en的话,由于我浏览器语言优先级是zh>ja,也是雅黑)。
对于指定了system-ui的场合,Firefox的逻辑是和其他西文字体完全一样的,对于CJK字符会根据语言选择fallback字体。唯一的区别在于这里对于lang=en的场合他是选用了有衬线字体TNR,因为Firefox字体设置里对于Latin的默认比例字体是衬线而不是无衬线。不过一般网站的CSS都会在字体最后指定sans-serif,所以实践中不会见到。
补充:我后来听说,Firefox似乎其实根本就不支持system-ui这个关键字。所以其效果等价于根本不加这个关键词。但是上面的分析的结论也没错就是了。
而Chrome那边如上文所述,会直接选用雅黑。由于雅黑字符集全,自然所有字符都雅黑了。假名巨丑,中日不同形的字符也会变成中文字形(这里的“将”)。另外,Chrome对于lang=en汉字会fallback到宋体而不是微软雅黑也是个多年以来的quirk了,我倒是不是特别不喜欢宋体所以不是太有所谓。
另外,强调一遍以上的都是在简中系统测试的。如果你的系统是英文,那默认字体则是Segoe UI,所以是从小(字符集)往大(字符集)fallback,不会受到雅黑的污染。
Workaround
在Chrome 78之前,我是使用了一个全局的Stylus rule来对付system-ui的:
@font-face {
font-family: system-ui;
src: local("Segoe UI");
}
但是在Chrome 79之后,你无法再使用@font-face来重新定义保留关键字了,说是这样才符合标准(那个标准我读了几遍都读不出这层意味,专门去CSSWG问了下,不过那边的专家都说确实不应该能覆盖。另外,Firefox从来就不支持用@font-face覆盖generic keyword。)
既然现在不行了,那只好手动替换Twitter了:
@-moz-document domain("twitter.com") {
* {
font-family: "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif !important;
}
}
顺便一提,我还替换了几个在Windows字体渲染效果极差的字体:
@font-face {
font-family: "M PLUS 1p";
src: local("Meiryo");
}
@font-face {
font-family: "mplus-1p-regular";
src: local("Meiryo");
}
@font-face {
font-family: "M PLUS 1p";
font-weight: bold;
src: local("Meiryo Bold");
}





