首页 / Astro 教程 / 自定义字体:@astrojs/fonts 与自托管

Astro 教程

自定义字体:@astrojs/fonts 与自托管

本教程共 56 篇 · 第 24 篇 · 更新于 2026-08-07 · 约 9 分钟阅读

AstroAstro 教程自定义字体Astro 字体FontsourceWeb 字体字体优化@astrojs/fonts

本节目标:搞懂 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(),给 namecssVariable”:

  • GooglefontProviders.google(),直接用 Google 字体。
  • AdobefontProviders.adobe(),用 Adobe Fonts。
  • BunnyfontProviders.bunny(),用 Bunny Fonts(隐私友好、不追踪用户)。
  • FontsharefontProviders.fontshare()
  • NPMfontProviders.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.mjsfonts 登记(本地文件用 fontProviders.local(),开源字体用 fontProviders.fontsource() 等),再用 <Font cssVariable="..." /> 挂到页面 head;接着讲了预加载、Tailwind 登记、变量字体、兜底字体与按需下载。整个过程 Astro 帮你做了优化与缓存,既快又护隐私。下一章我们看图片和视频的“托管服务”。