搜索全站
主题 12 分钟阅读

主题字体本地化:移除 Google Fonts 的合规与提速收益

主题默认加载 Google Fonts 导致国内打开慢、合规有风险?本文给出定位并移除外部字体请求、下载 woff2 自托管、配 preload 与 font-display 的完整做法。

U
UFO_PF 2022-02-22 · 阅读 12 分钟
主题 主题
阅读提示
本文约 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 最简洁 影响所有匹配资源
主题选项里关闭 最干净 并非所有主题提供

保姆级实操

  1. 先找出所有外部字体请求:打开页面源码搜索 fonts.googleapis.com,记录 handle 与 URL;也可用 wp style 相关命令或从 wp_styles()->registered 里列。
  2. 下载字体文件:从 Google Fonts 网站下载对应字重的 woff2(中文站建议改用系统字体栈,中文字体子集化另说)。
  3. 放进主题目录:建议 assets/fonts/,注意目录权限与大小写。
  4. 移除外部请求:在子主题里用通用方式摘掉所有 Google Fonts 样式;优先级要足够晚(如 wp_enqueue_scripts 的 100),确保主题已注册完。
  5. 声明 @font-face:自己写一份 CSS,src 指向本地 woff2,务必加 font-display: swap。
  6. 加 preload:只对首屏真正用到的 1–2 个字体文件 preload,多了反而抢占带宽。
  7. 验证:刷新后看 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 放置位置。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。