自定义字体:@astrojs/fonts 与自托管
本教程共 56 篇 · 第 24 篇 · 更新于 2026-08-07 · 约 9 分钟阅读
本节目标:搞懂 Astro 怎么加“非系统自带”的字体,学完你能用配置登记本地字体或 Fontsource 字体,并用 Font 组件把它应用到页面。
字体是什么,为什么要管
网页默认用的是操作系统自带的字体。想用更有个性的字体(比如某个开源字体),就得自己“引进来”,这类字体叫 Web 字体(Web fonts)。
但字体文件不小,引得不好会让页面变慢、甚至闪一下(文字先用品替字体、加载完才换成目标字体)。Astro 提供了一套统一的 Fonts API,帮你自动做优化:自动加预加载链接、生成更好的兜底字体、下载后缓存到自己站点,既快又保护隐私(用户数据不用发给第三方字体站)。
Note这套能力对应官方文档的“Using custom fonts”指南。它内置支持多家字体来源:Adobe、Bunny、Fontshare、Fontsource、Google、Google Icons、NPM,也支持你自己的本地字体文件。
第一步:在配置里登记字体
所有字体都在 astro.config.mjs 里用 fonts 选项登记。每个字体要写三样:名字(name)、对应的 CSS 变量(cssVariable)、以及字体来源(provider)。
用本地字体文件
假设你有个字体文件 DistantGalaxy.woff2,放在 src/assets/fonts/。
先装包并登记:
import { defineConfig, fontProviders } from "astro/config";
export default defineConfig({
fonts: [{
provider: fontProviders.local(),
name: "DistantGalaxy",
cssVariable: "--font-distant-galaxy",
options: {
variants: [{
src: ['./src/assets/fonts/DistantGalaxy.woff2'],
weight: 'normal',
style: 'normal'
}]
}
}]
});
variants 里写明字体文件的路径、字重(weight)、字形(style)。登记完,这个字体就“备好”了,等下挂到页面上就能用。
用 Fontsource(含 Google 字体)
Fontsource 是个开源项目,能让你方便地用 Google 字体等开源字体。比如用 Roboto:
import { defineConfig, fontProviders } from "astro/config";
export default defineConfig({
fonts: [{
provider: fontProviders.fontsource(),
name: "Roboto",
cssVariable: "--font-roboto",
}]
});
Adobe、Bunny 等同体系的来源写法几乎一样,只是把 fontsource() 换成对应的 provider。
第二步:用 Font 组件挂到页面
字体登记好,还得“挂”到页面的 <head> 里,它才真正生效。用 <Font /> 组件,必填属性是 cssVariable(要和配置里写的变量名一致)。通常放在布局组件(layout)的 head 里,这样全站页面共用:
---
import { Font } from "astro:assets";
---
<html>
<head>
<Font cssVariable="--font-distant-galaxy" />
</head>
<body>
<slot />
</body>
</html>
然后,在任意用这个布局的页面里,就能用那个 CSS 变量来指定字体:
---
import Layout from "../layouts/Layout.astro";
---
<Layout>
<h1>在很远很远的星系……</h1>
<p>自定义字体让我的标题更酷!</p>
<style>
h1 {
font-family: var(--font-distant-galaxy);
}
</style>
</Layout>
这样只有 <h1> 用了自定义字体,<p> 还是默认字体。
预加载关键字体
字体预加载(preload)能让“首屏立刻要看的字”更快显示。但别滥用——预加载会占用带宽、还可能加载了用不上的字体。一般只预加载首屏最关键的那个字体:
---
import { Font } from "astro:assets";
---
<html>
<head>
<Font cssVariable="--font-distant-galaxy" preload />
</head>
<body>
<slot />
</body>
</html>
在 Tailwind 里登记字体
如果你用 Tailwind 排版,字体不是用 font-face 直接写的,而是在 Tailwind 配置里登记:
Tailwind 4 在 global.css 里:
@import "tailwindcss";
@theme inline {
--font-sans: var(--font-roboto);
}
Tailwind 3 在 tailwind.config.mjs 里:
export default {
theme: {
extend: {},
fontFamily: {
sans: ["var(--font-roboto)"]
}
},
plugins: []
};
登记后,Tailwind 的 font-sans 等工具类就会用上你的自定义字体。
变量字体:一个文件管多种字重
普通字体每种字重(细、常规、粗)是单独文件。变量字体(variable font)则把一整个字重范围塞进一个文件,更省事。配置时把 weight 写成范围即可:
import { defineConfig, fontProviders } from "astro/config";
export default defineConfig({
fonts: [{
provider: fontProviders.local(),
name: "Inter",
cssVariable: "--font-inter",
options: {
variants: [
{
weight: "100 900",
style: "normal",
src: ["./src/assets/fonts/InterVariable.woff2"],
},
],
},
}]
});
用 Fontsource 这类支持变量字体的来源时,则把 weights 写成一个范围数组,比如 weights: ["300 700"]。
兜底字体:避免加载时“跳一下”
兜底字体(fallback)指:当主字体还没加载好、或缺少某个字时,用来顶替的字体。如果兜底字体和主字体长得差太多,页面加载时文字会“跳一下”。
Astro 会从你配置的最后一个兜底(默认 sans-serif)自动生成一个“优化过的兜底”,尽量贴合主字体形状,减少跳动。你也可以自己指定:
export default defineConfig({
fonts: [{
provider: fontProviders.fontsource(),
name: "Cousine",
cssVariable: "--font-cousine",
fallbacks: ["monospace"]
}]
});
若想关掉这套自动优化,把 font.optimizedFallbacks 设为 false,Astro 就直接用你写的兜底、不再额外处理。
按需下载,少引少吃
Fonts API 很“懂事”:你可以精细控制只下载真正用到的字重和字形组合。同一个字体(变量名、名字、来源都一样)可以写多次、每次不同的组合,Astro 会合并并只下载需要的文件。比如正常体下载 500 和 600,斜体只下载 500:
export default defineConfig({
fonts: [
{
name: "Roboto",
cssVariable: "--roboto",
provider: fontProviders.google(),
weights: [500, 600],
styles: ["normal"]
},
{
name: "Roboto",
cssVariable: "--roboto",
provider: fontProviders.google(),
weights: [500],
styles: ["italic"]
}
]
});
内置字体来源一览
除了前面演示的本地文件和 Fontsource,Astro 还内置了这些 provider,用法大同小异——都是“在配置里写 provider: fontProviders.xxx(),给 name 和 cssVariable”:
- Google:
fontProviders.google(),直接用 Google 字体。 - Adobe:
fontProviders.adobe(),用 Adobe Fonts。 - Bunny:
fontProviders.bunny(),用 Bunny Fonts(隐私友好、不追踪用户)。 - Fontshare:
fontProviders.fontshare()。 - NPM:
fontProviders.npm(),从 npm 上的字体包引入。 - 本地文件:
fontProviders.local(),前面已演示。
选哪个取决于你想要的字体在哪个平台,以及你对隐私、加载速度的偏好。比如在意隐私,可优先考虑 Bunny 或自托管本地文件。
一个多字体配置示例
实际项目往往要同时挂好几个字体。下面是一份“综合配置”的简化版,展示一个站点同时登记 Roboto(Google)、Inter(Fontsource,限定字重和字符集)、JetBrains Mono(等宽,用于代码)、Poppins(本地文件)的做法:
import { defineConfig, fontProviders } from "astro/config";
export default defineConfig({
fonts: [
{
name: "Roboto",
cssVariable: "--font-roboto",
provider: fontProviders.google(),
},
{
name: "Inter",
cssVariable: "--font-inter",
provider: fontProviders.fontsource(),
weights: [400, 500, 600, 700],
styles: ["normal"],
subsets: ["latin", "cyrillic"],
formats: ["woff2", "woff"],
},
{
name: "JetBrains Mono",
cssVariable: "--font-jetbrains-mono",
provider: fontProviders.fontsource(),
subsets: ["latin", "latin-ext"],
fallbacks: ["monospace"],
},
{
name: "Poppins",
cssVariable: "--font-poppins",
provider: fontProviders.local(),
options: {
variants: [
{ src: ["./src/assets/fonts/Poppins-regular.woff2", "./src/assets/fonts/Poppins-regular.woff"] },
{ src: ["./src/assets/fonts/Poppins-bold.woff2", "./src/assets/fonts/Poppins-bold.woff"] },
]
}
}
],
});
subsets 用来只下载页面真正用到的字符集,能进一步减小体积;formats 控制输出哪些字体格式。这样一份配置就能让全站的不同文字(正文、代码、标题)各用各的字体。
不同页面用不同字体
一个项目常有多套字体:正文一套、代码一套、标题一套。<Font /> 可以按页面分别挂——只要把它们都放进对应布局的 <head>,每个 <Font /> 用各自的 cssVariable 区分即可:
---
import { Font } from "astro:assets";
---
<html>
<head>
<Font cssVariable="--font-roboto" />
<Font cssVariable="--font-jetbrains-mono" />
</head>
<body>
<slot />
</body>
</html>
之后正文用 font-family: var(--font-roboto),代码块用 var(--font-jetbrains-mono),互不干扰。如果某个字体只出现在特定页面,把它放进那个页面的布局就行,不必全站都挂,免得无关页面也下载用不到的字重。
前面说过,预加载(preload)只给首屏最关键的字体用。一个常见做法是:全局布局里只 preload 正文字体,其余字体(如代码字体)不预加载,等用到再加载,这样首屏带宽留给真正立刻要看的字。
缓存与隐私
用 Fonts API,字体文件会被下载并缓存在你自己的站点(构建时放进 _astro/fonts,享受静态资源一年的 HTTP 缓存)。好处有两层:一是访问快、可缓存;二是用户数据不必发给 Google 等第三方字体站,更隐私。开发时想清缓存,删掉 .astro/fonts 目录即可。
进阶:程序里访问字体数据
少数高级场景(比如用 Satori 在 API 路由里生成 OpenGraph 分享图)需要直接拿到字体文件。Astro 暴露了低层 API:fontData 对象能列出已下载的所有字体文件及元数据,experimental_getFontFileURL() 函数能拿到某个字体文件的可用网址。这类用法属于进阶,普通排版用不到,但知道有这条路就好。
小结
本章我们走通了 Astro 自定义字体的两步法:先在 astro.config.mjs 用 fonts 登记(本地文件用 fontProviders.local(),开源字体用 fontProviders.fontsource() 等),再用 <Font cssVariable="..." /> 挂到页面 head;接着讲了预加载、Tailwind 登记、变量字体、兜底字体与按需下载。整个过程 Astro 帮你做了优化与缓存,既快又护隐私。下一章我们看图片和视频的“托管服务”。