WordPress 用一行 CSS 改默认中文字体为微软雅黑
保哥这些年帮人调过几十个 WordPress 站点,被吐槽最多的不是排版,也不是配色,而是“中文字体看着特别糊”。问题本质上不复杂:很多 WordPress 主题,尤其是国外作者写的主题,font-family 里只列了 Arial、Helvetica、sans-serif 这一类英文字体栈,没指定中文字体,浏览器只能拿系统默认的宋体或者衬线字体来渲染中文,于是页面看起来就是“一股 Windows XP 的味道”。这篇笔记把保哥常年使用的一行 CSS 改字体方案、为什么这一行就够用、怎么避免破坏 Font Awesome 图标、以及多端字体适配的进阶玩法都整理出来,给同样被默认字体劝退的朋友抄作业。
一、为什么 WordPress 默认中文字体显得特别糊
保哥先把根因讲清楚。一个 WordPress 主题在 style.css 里通常这样写:
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}这串字体栈对英文渲染没有任何问题,但里面没有任何一项是中文字体。Windows 浏览器在拿不到中文字体声明时会回退到系统默认的中文字体,往往是“宋体”或者带衬线的渲染方式;macOS 会回退到“PingFang SC”,本身就好看;而很多老旧的国产 Chromium 套壳浏览器还会强行用一些自带字体,最终在不同访客那里呈现的样子千差万别。
站长侧能控制的只有一件事:在主题 CSS 里把中文字体显式声明出来,让所有现代浏览器都优先使用约定好的字体。保哥之所以选择微软雅黑,是因为它在 Windows 上覆盖率最高,macOS 用户会自动落到 PingFang SC,移动端会落到“苹方”或者“思源黑体”,整体观感会一致很多。
二、保哥常用的一行 CSS:原理拆解
保哥的“保哥笔记”主站这些年只用了一行 CSS 来修这个问题:
*:not([class*="icon"]):not(i) {
font-family: "Segoe UI", "Microsoft Yahei", sans-serif !important;
}看起来短,里面其实有四个值得拆开讲的细节。
第一个细节是 * 选择器。它会命中页面上所有元素,相当于一刀切地把字体替换成微软雅黑。比起一个个去找 body、h1、p、a 来声明,这种写法最不容易遗漏。
第二个细节是 :not([class*="icon"])。这是用来把所有类名里包含 icon 的元素排除掉,最常见的就是 Font Awesome 的 fa-xxx、icon-xxx、Material Icons 的 material-icons 等等。这些图标其实是用字体文件渲染的特殊字形,如果被强制改成微软雅黑,就会变成方块或者乱码。
第三个细节是 :not(i)。历史上 <i> 标签经常被用作图标占位(Bootstrap 早期主题、各种社交分享按钮都喜欢用 <i class="fa fa-xxx"></i>),单独把 i 标签排除掉是双保险。
第四个细节是 !important。WordPress 主题的 CSS 优先级各家写法不一致,有的主题在 body.home 里又重新声明了一遍 font-family,不加 !important 会被覆盖。加上之后就能稳定生效,副作用是后续如果想再改字体,需要明确知道是这一行在起作用。
三、把这行 CSS 放在哪里:三种推荐位置
保哥实测下来,下面三种位置都能让这行 CSS 生效,但适用场景不同。
第一种是 WordPress 自带的“外观 → 自定义 → 额外 CSS”。这是最推荐的方式,所有用户级 CSS 都集中在一处,主题更新不会丢失,关闭也只要把这行删掉即可。绝大多数情况选这个就够了。
第二种是子主题的 style.css。如果项目里已经做了子主题,可以把这行写到子主题里,配合版本控制更方便维护。但要注意子主题的 CSS 必须通过 wp_enqueue_style 正常加载,否则不会生效。
第三种是放进主题的 functions.php,用钩子动态注入:
// functions.php
add_action('wp_head', function () {
echo '<style>*:not([class*="icon"]):not(i){font-family:"Segoe UI","Microsoft Yahei",sans-serif !important;}</style>';
}, 100);这种做法适合需要根据用户登录状态、设备类型动态切换字体的场景,但写法上比直接放“额外 CSS”要繁琐,保哥不推荐入门用户这么干。
四、Font Awesome 与 emoji 的避坑要点
保哥被读者问过最多的一句话是:“按你那行写完之后,我的图标全变成方块了,是不是写错了?”大概率是漏掉了 :not 这部分。下面把容易踩坑的几种情况列出来。
如果使用 Font Awesome 6 的 SVG 模式,图标是 SVG 节点而不是字体字形,几乎不受 font-family 影响,可以放心。如果使用 Font Awesome 4/5 的字体模式,图标渲染依赖 FontAwesome 这个字体族,需要靠 :not([class*="icon"]) 排除,所以那一行不能省。
如果是阿里图标库 iconfont,它的类名通常是 iconfont icon-xxx,同样会被 [class*="icon"] 命中并排除,没问题。如果你用的是 Material Symbols,类名是 material-symbols-outlined,里面没有 icon 字符串,需要在 :not 里再加一项:
*:not([class*="icon"]):not(i):not([class*="material"]) {
font-family: "Segoe UI", "Microsoft Yahei", sans-serif !important;
}至于 emoji,主流系统会优先用系统自带的彩色 emoji 字体(Apple Color Emoji、Segoe UI Emoji 等),不会被 font-family 覆盖到普通文本字体上去,因此一般不需要额外处理。
五、面向多端与高分屏的进阶字体栈
保哥笔记早期就是这一行 CSS,但站点流量上来之后,移动端用户占比超过六成,单写微软雅黑就显得不够细腻。下面这套是保哥近两年在用的多端字体栈,给追求观感的同行参考:
*:not([class*="icon"]):not(i):not([class*="material"]) {
font-family:
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
"PingFang SC",
"Hiragino Sans GB",
"Microsoft Yahei",
"Source Han Sans CN",
sans-serif !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}这套写法的逻辑是:iOS / macOS 优先用系统的 -apple-system,自动落到“苹方”;Windows 优先用“Segoe UI”,中文落到“微软雅黑”;安卓优先用“思源黑体 CN”;其他情况再回退到 sans-serif。
下面三行字体平滑相关的属性看似可有可无,但在高分屏(视网膜、2K、4K)上观感差距非常明显。-webkit-font-smoothing: antialiased 会让笔画更细更轻,text-rendering: optimizeLegibility 会让 Kerning 更自然。保哥实测在 macOS Safari 上开启之后,正文阅读疲劳感明显下降。
六、常见问题 FAQ
Q1:保哥,加了这行 CSS 之后我的代码块字体也变了,能让代码块继续用等宽字体吗?
可以。在那行 CSS 之后再加一条更具体的规则,把 pre、code、kbd、samp 这几个标签恢复成等宽字体即可。例如:pre, code, kbd, samp { font-family: "Cascadia Code", Consolas, "Courier New", monospace !important; }。因为后写的 CSS 优先级相同时会覆盖前面的,所以代码块能正常显示等宽字体。
Q2:为什么我加了之后没生效,必须强刷才能看到?
这是浏览器和 CDN 缓存导致的。WordPress 自带的“额外 CSS”会通过 ?ver= 参数避免缓存,但如果你站点前面挂了 Cloudflare、又拉、阿里云 DCDN 这类服务,CSS 文件会被缓存几分钟到几十分钟。最快的做法是去 CDN 控制台清一次缓存,然后用无痕窗口访问。
Q3:用微软雅黑会不会有版权风险?
微软雅黑只随 Windows 系统授权,商业用途上把字体文件放到自己服务器分发是有风险的。但保哥这行 CSS 只是写了 font-family: "Microsoft Yahei",并没有把字体文件拷到服务器,访客是用自己电脑里 Windows 自带的字体来渲染,因此没有版权问题。如果是要把网页字体打包嵌入应用里分发,需要另行申请商用授权。