使用 Claude Code 优化 Web 字体的实战指南
用 Claude Code 安全优化 Web 字体:preload、font-display、子集化、CLS/LCP 与验证流程。
字体优化首先是渲染稳定性问题
Web 字体不只是视觉风格。加载策略错误时,页面会出现空白文字、标题突然换行、按钮位置跳动,甚至让 LCP 变慢。LCP 是 Largest Contentful Paint,意思是首屏最大内容元素完成显示所需的时间。CLS 是 Cumulative Layout Shift,意思是页面元素在加载过程中发生的意外位移。中文、日文、韩文等大字符集字体通常更重,所以一个字体文件就可能拖慢首屏。
这篇文章以 Astro 网站为例,说明如何让 Claude Code 安全地实现字体优化。我们会覆盖加载策略、preload、preconnect、font-display、可变字体、字体子集化、自托管和第三方字体的取舍、CLS/LCP 风险、Lighthouse 与 WebPageTest 风格的检查,以及可以直接复制给 Claude Code 的提示词。
事实性判断以官方文档为准。MDN 解释了font-display的不同模式,也说明了rel="preload"中字体资源需要正确声明类型和跨域属性。整体最佳实践可以参考 web.dev 的字体最佳实践、Web 字体优化以及Web Vitals。
先决定加载策略,再让 Claude Code 改代码
不要直接说“帮我优化字体”。这样的指令太宽,Claude Code 可能会到处加preload,或者删除设计中仍然需要的字重。先回答三个问题:首屏必须显示哪些文字,品牌字体是否真的必须用于正文,哪些字体可以延后或删除。
| 场景 | 推荐策略 | 好处 | 常见失败 |
|---|---|---|---|
| 多语言博客正文 | 正文先用系统字体,标题使用子集化 Web 字体 | 即使字体慢,读者也能立即阅读 | 把标题字体误用到全文 |
| SaaS 控制台 | 自托管 Inter 等拉丁可变字体 | 多个字重可由一个文件覆盖 | 未使用的斜体、轴或语言范围仍被打包 |
| 营销落地页首屏 | 只预加载 LCP 标题实际使用的 WOFF2 | 首屏销售文案更早出现 | 把所有字重都预加载,抢走图片带宽 |
| 旧 icon font | 改成 SVG 或组件图标 | 减少一个字体请求 | 伪元素样式没有同步迁移 |
博客页面通常不需要全文强制使用 Web 字体。正文越长,越应该先保证可读性,再把品牌感留给标题、导航或 CTA。SaaS 管理界面则不同,它通常有大量数字、标签和按钮,使用一个拉丁可变字体更容易统一视觉。落地页要把字体和 hero 图片一起看,因为两者都会影响首屏。相关图片策略可以参考Claude Code 图片优化指南,整体速度优化可以继续看Claude Code 性能优化。
在 Astro 中实现 preload 和 preconnect
preload是很强的浏览器提示,只适合首屏一定会用到的一两个字体文件。不要把所有字重、所有语言、滚动后才出现的字体都预加载。自托管字体时,通常不需要preconnect。使用 Google Fonts 等第三方服务时,才需要考虑对 CSS 域名和字体文件域名预连接。
---
// src/layouts/BaseLayout.astro
const criticalFonts = [
{ href: "/fonts/inter-var-latin.woff2", type: "font/woff2" },
{ href: "/fonts/noto-sans-jp-latin-kana.woff2", type: "font/woff2" },
];
const usesGoogleFonts = false;
---
<html lang="zh">
<head>
{criticalFonts.map((font) => (
<link rel="preload" href={font.href} as="font" type={font.type} crossorigin />
))}
{usesGoogleFonts && <link rel="preconnect" href="https://fonts.googleapis.com" />}
{usesGoogleFonts && <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />}
<link rel="stylesheet" href="/styles/fonts.css" />
</head>
<body>
<slot />
</body>
</html>
审查时看三点。第一,href必须和@font-face里的src一致。第二,as="font"、type="font/woff2"、crossorigin要齐全。第三,被预加载的字体必须在首屏很快使用。如果浏览器提示“preloaded but not used”,应该减少预加载,而不是忽略警告。
font-display 需要和回退字体一起设计
font-display: swap会先用回退字体显示文字,然后在 Web 字体到达后替换。它可以减少不可见文字,但如果回退字体和目标字体的宽度、行高差异太大,替换时仍然会造成 CLS。optional适合不关键的正文或弱网场景,因为浏览器可以选择继续使用回退字体,而不是很晚才替换。
/* public/styles/fonts.css */
@font-face {
font-family: "InterVariable";
src: url("/fonts/inter-var-latin.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "NotoSansJPSubset";
src: url("/fonts/noto-sans-jp-latin-kana.woff2") format("woff2");
font-weight: 400 700;
font-style: normal;
font-display: swap;
unicode-range: U+0000-00FF, U+3000-30FF, U+FF00-FFEF;
}
@font-face {
font-family: "InterFallback";
src: local("Arial");
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
:root {
--font-ui: "InterVariable", "InterFallback", system-ui, sans-serif;
--font-ja: "NotoSansJPSubset", "Hiragino Sans", "Yu Gothic", sans-serif;
}
body {
font-family: var(--font-ui);
}
article {
font-family: var(--font-ja);
}
MDN 的unicode-range说明了如何让一个@font-face只负责部分字符范围。注意,它不会自动让文件变小。想减少字节,仍然要生成更小的 WOFF2 文件。
用可变字体和子集化减少字节
可变字体可以用一个文件覆盖多个字重,适合按钮、导航、表格和管理后台等 UI。它不一定总是更小。如果包含很多轴、斜体或语言范围,文件仍然可能很大。让 Claude Code 先统计真实使用的字重和脚本,再决定是否替换。
子集化是把字体中暂时不需要的字符移除。它适合首屏标题、导航、固定 CTA 和拉丁/假名范围。对正文使用时要谨慎,因为新文章可能引入子集中没有的字符,结果页面会混用多种字体。
# Create a WOFF2 subset with Latin, punctuation, kana, and full-width forms.
python -m pip install "fonttools[woff]"
mkdir -p public/fonts
pyftsubset ./vendor-fonts/NotoSansJP-Regular.ttf \
--output-file=./public/fonts/noto-sans-jp-latin-kana.woff2 \
--flavor=woff2 \
--layout-features='*' \
--unicodes="U+0000-00FF,U+3000-30FF,U+FF00-FFEF"
这个命令故意不包含大部分汉字。它适合标题、导航和固定文案,不适合完整正文。如果要覆盖正文,需要从 MDX 或模板中抽取实际字符,生成--text-file,或者准备单独的汉字子集。还要检查字体许可证,确认自托管、修改和再分发都被允许。
自托管和第三方字体的取舍
自托管的优势是 URL 稳定、缓存可控、preload目标明确、子集化自由。代价是你要维护文件、许可证、更新和构建脚本。第三方字体上线快,但会增加外部连接和 CSS 请求,并且实际字体 URL 可能由提供方 CSS 决定。
| 判断点 | 自托管 | 第三方 |
|---|---|---|
| 连接 | 只访问本站 | 需要 DNS、TLS、CSS 域和字体域 |
| 缓存 | 可以使用文件指纹和长期缓存 | 依赖提供方响应头 |
| 子集化 | 可完全控制 | 取决于服务能力 |
| 运维 | 责任更多 | 上手更快但外部依赖更多 |
性能敏感页面通常把首屏关键字体自托管,装饰字体延迟加载。快速原型可以使用第三方字体,但要使用display=swap,只连接必要域名,只加载实际使用的字重。不要同时保留 Google Fonts CSS 和自托管 CSS,否则浏览器可能下载两套字体。
用 Lighthouse 和 WebPageTest 风格检查结果
优化完成后,不要只看页面有没有变好看。Lighthouse 可以给出 LCP、CLS 和字体显示相关提示。然后用浏览器网络面板或 WebPageTest 的思路看瀑布图:HTML、CSS、关键字体、hero 图片和 JavaScript 的顺序是否合理。
URL="https://example.com/"
npx --yes lighthouse "$URL" \
--only-categories=performance \
--chrome-flags="--headless" \
--output=json \
--output-path=./lighthouse-fonts.json
node -e "const r=require('./lighthouse-fonts.json'); for (const id of ['largest-contentful-paint','cumulative-layout-shift','font-display']) console.log(id, r.audits[id]?.displayValue ?? r.audits[id]?.score ?? 'n/a')"
检查瀑布图时,关键字体应该早开始,但不能阻塞首屏 CSS 或图片。重复访问时字体应该来自缓存。同一个 WOFF2 不应下载两次。慢速移动网络下,正文应立即可读。字体替换时标题、价格、按钮和广告位不能跳动。
常见坑包括:预加载了首屏没有使用的粗体;迁移到自托管后忘了删除 Google Fonts CSS;只加了font-display: swap却没有调整回退字体;子集中漏掉全角数字、标点或长音符号;把 icon font 当成普通文字字体继续预加载。
给 Claude Code 的安全提示词
先让 Claude Code 只审计,不要编辑。
Audit web font loading in this Astro site. Do not edit files yet.
Find:
- @font-face, Google Fonts, Fontsource, and CSS import locations
- Font files used above the fold
- preload and preconnect hints that are missing or unnecessary
- CLS or LCP risks caused by font swapping
- Candidates for self-hosting, variable fonts, and subsetting
Return:
- A prioritized table of changes
- Files that should be edited and files that must not be touched
- Verification commands and residual risks
确认方案后,再限制编辑范围。
Implement web font optimization only in these files:
- src/layouts/BaseLayout.astro
- public/styles/fonts.css
- generated files under public/fonts/
Acceptance criteria:
- Preload only WOFF2 files used in the first viewport
- Do not add preconnect when fonts are self-hosted
- Every @font-face has a deliberate font-display value
- Fallback metrics are adjusted to reduce CLS
- Existing routes, article slugs, hero images, and unrelated content are untouched
Verification:
- npm run build
- node scripts/check-code-fences.mjs
- Lighthouse check for LCP, CLS, and font-display
- Report what could not be verified
实际验证结果和 CTA
Masa 的实际经验是,明确“只预加载 LCP 标题使用的字体,正文保持系统字体可读”比笼统要求“优化字体”更稳定。日文内容页中,先加载拉丁和假名子集后首屏更稳,但正文完整覆盖仍需要字符抽取流程。最终最有价值的检查不是单个 Lighthouse 分数,而是慢速移动网络瀑布图加上人工观察标题和 CTA 是否跳动。
如果要把这套做法放进团队流程,请把字体规则写入CLAUDE.md。可以先用免费速查表固定安全命令,再用产品模板整理提示词和审查清单。需要把 Core Web Vitals、文章质量和收益 CTA 一起改善时,可以看Claude Code 培训与导入咨询。
发布前自检:本文包含 3 个以上实际用例、Astro/CSS/bash 示例、官方 MDN 和 web.dev 外部链接、内部链接、具体失败模式、自然 CTA,以及实际验证结果说明。
免费 PDF: Claude Code 速查表
输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。
我们会妥善保护你的信息,不发送垃圾邮件。
把 Claude Code 变成真正能带来结果的工作流
先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。
关于作者
Masa
专注 Claude Code 实务流程、团队导入和内容转化的工程师。
相关文章
Claude Code Permission Receipt Pattern:记录权限、证据和回滚方式
Claude Code 权限 receipt:记录允许动作、需要批准的边界、验证命令、回滚说明,以及 Gumroad 和咨询 CTA 检查。
Claude Code/Codex 安全 Agent Harness 实战:权限、验证与回滚
用权限策略、执行计划、验证脚本和回滚日志,为 Claude Code 与 Codex 搭建更安全的 AI Agent 工作流。
Claude Code 子代理实战指南:安全委派并行文章与代码工作
用 Claude Code 子代理安全拆分文章和代码工作:委派规则、提示词模板、失败模式与检查清单。