本文约 4,501 字,预计阅读 12 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:一个字体请求,拖慢整站首屏
国内做站最常遇到的一类慢:页面本身不大,但打开时先卡在”正在等待 fonts.googleapis.com 响应”。主题默认从 Google Fonts 拉取字体,这个域名在国内访问不稳定,轻则首屏慢两三秒,重则一直挂着直到超时,文字迟迟不显示(FOIT)。
除此之外还有合规考量:欧洲已有法院判决认为,网站未经告知把访客 IP 传给第三方(包括字体 CDN)可能违反数据保护规定。对面向海外用户的站点,把字体自托管能直接消除这一风险。
好消息是这件事不复杂:找到字体请求的 handle → 移除 → 把 woff2 放进主题目录 → 用 @font-face 声明并加 font-display: swap。
原理分析:字体请求是怎么被塞进页面的
主题通常用 wp_enqueue_style( 'xxx-fonts', 'https://fonts.googleapis.com/css2?family=...' ) 排队一个外部样式表,这个样式表内部再声明 @font-face 指向 fonts.gstatic.com。所以页面上会出现两类外部请求:CSS 与字体文件。
移除有两种思路:
其一,精确移除:找到那个 handle,用 wp_dequeue_style() 摘掉。缺点是要先知道 handle 名,换主题或换版本可能变。
其二,通用拦截:遍历 wp_styles()->registered,凡 src 含 fonts.googleapis.com 的一律摘掉;或者用 style_loader_src 过滤器,对匹配的 URL 返回 false(核心会跳过该资源的输出)。通用做法更抗变更,适合子主题长期维护。
字体文件本身建议只保留 woff2(现代浏览器全支持,体积最小),并用 font-display: swap 让文字先用系统字体渲染,字体到位后再替换,彻底消除 FOIT。首屏关键字体可用 <link rel="preload"> 提前拉取。
| 方案 | 优点 | 缺点 |
|---|---|---|
精确 wp_dequeue_style |
直观 | handle 变更即失效 |
| 遍历 registered 移除 | 抗变更 | 需挂在足够晚的优先级 |
style_loader_src 返回 false |
最简洁 | 影响所有匹配资源 |
| 主题选项里关闭 | 最干净 | 并非所有主题提供 |
保姆级实操
- 先找出所有外部字体请求:打开页面源码搜索
fonts.googleapis.com,记录 handle 与 URL;也可用wp style相关命令或从wp_styles()->registered里列。 - 下载字体文件:从 Google Fonts 网站下载对应字重的
woff2(中文站建议改用系统字体栈,中文字体子集化另说)。 - 放进主题目录:建议
assets/fonts/,注意目录权限与大小写。 - 移除外部请求:在子主题里用通用方式摘掉所有 Google Fonts 样式;优先级要足够晚(如
wp_enqueue_scripts的 100),确保主题已注册完。 - 声明
@font-face:自己写一份 CSS,src指向本地 woff2,务必加font-display: swap。 - 加 preload:只对首屏真正用到的 1–2 个字体文件 preload,多了反而抢占带宽。
- 验证:刷新后看 Network 面板,确认不再有
fonts.googleapis.com/fonts.gstatic.com请求,且文字正常显示。
<?php
// 1) 通用移除:摘掉所有指向 Google Fonts 的样式
add_action( 'wp_enqueue_scripts', 'mimangfei_remove_google_fonts', 100 );
function mimangfei_remove_google_fonts() {
$styles = wp_styles();
foreach ( $styles->registered as $handle => $dep ) {
if ( ! empty( $dep->src ) && false !== strpos( $dep->src, 'fonts.googleapis.com' ) ) {
wp_dequeue_style( $handle );
wp_deregister_style( $handle );
}
}
}
// 2) 备选:用过滤器让匹配的资源不输出(更彻底,含内联注册的场景)
add_filter( 'style_loader_src', 'mimangfei_block_google_fonts_src', 100 );
function mimangfei_block_google_fonts_src( $src ) {
if ( $src && false !== strpos( $src, 'fonts.googleapis.com' ) ) {
return false;
}
return $src;
}
// 3) 排队本地字体样式
add_action( 'wp_enqueue_scripts', 'mimangfei_local_fonts', 101 );
function mimangfei_local_fonts() {
$file = get_stylesheet_directory() . '/assets/css/fonts.css';
if ( file_exists( $file ) ) {
wp_enqueue_style( 'mf-fonts', get_stylesheet_directory_uri() . '/assets/css/fonts.css', array(), filemtime( $file ) );
}
}
/* assets/css/fonts.css —— 本地字体声明 */
@font-face {
font-family: "Inter";
src: url("../fonts/inter-regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter";
src: url("../fonts/inter-semibold.woff2") format("woff2");
font-weight: 600;
font-style: normal;
font-display: swap;
}
:root {
/* 中文站优先使用系统字体栈,不额外下载中文字体 */
--font-body: "Inter", system-ui, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
}
body {
font-family: var(--font-body);
}
<?php
// 4) 首屏关键字体 preload(只对 1~2 个文件做,别贪多)
add_action( 'wp_head', 'mimangfei_preload_font', 1 );
function mimangfei_preload_font() {
printf(
'<link rel="preload" href="%s" as="font" type="font/woff2" crossorigin>' . "\n",
esc_url( get_stylesheet_directory_uri() . '/assets/fonts/inter-regular.woff2' )
);
}
# 5) 验证:确认页面里已无 Google Fonts 相关请求
curl -s https://example.com/ | grep -o "fonts\.googleapis\.com\|fonts\.gstatic\.com" | sort -u
# 无输出即表示已清理干净
常见踩坑
- 只摘掉了 CSS,忘了
@font-face里的fonts.gstatic.com请求仍在(自托管后自然消失)。 - 移除优先级太低(默认 10),主题还没注册完就执行,摘不掉。
- 忘了加
font-display: swap,文字依然空白等待。 - 把整套中文字体(动辄数 MB)也自托管,页面体积暴涨——中文字体应优先走系统字体栈或做子集化。
- 案例:某站做完字体本地化后首屏反而更慢。排查发现 preload 了 6 个字体文件,带宽被字体占满,LCP 图片排在后面。改成只 preload 正文字体、其余靠
font-display: swap兜底后,LCP 从 3.4s 降到 1.9s。 - 字体文件路径写错,控制台报 404,页面回落到默认衬线字体,看起来”字体没生效”。
- 用了 CDN 后没同步字体文件的 CORS 头,跨域字体被拦截(表现为字体加载失败)。
总结
字体本地化的收益是双重的:国内访问提速(少一个不可控的外部域名)+ 合规风险消除(不再向第三方泄露访客 IP)。判断标准是”Network 面板里没有 fonts.googleapis.com / fonts.gstatic.com,且首屏文字立即可见”。行动清单:① 用通用方式移除而非写死 handle;② 只保留 woff2;③ 必加 font-display: swap;④ preload 控制在 1–2 个;⑤ 中文走系统字体栈。延伸阅读 lumen-mimangfei 主题性能优化、WordPress 移除头部冗余输出 与 主题自定义 CSS 放置位置。
