跳转到内容

实验性字体 API

类型: FontFamily[]

添加于: astro@5.7.0

此实验性功能允许你通过统一、完全可定制且类型安全的 API,来使用这些来源的字体:本地文件系统,字体提供商(例如:Google、Fontsource、Bunny)。

网络字体会影响网页在加载时间和渲染时的性能。此 API 将通过自动化的 网页字体优化,包括预加载、自定义回退内容和强约定的默认配置来帮助你维持网站的高性能表现。查看常见的用法示例

字体 API 通过下载并缓存字体以从你的网站提供字体,从而专注于性能和隐私。这可以避免将用户数据发送到第三方站点,并确保为所有访客提供一致的字体集合。

要启用该功能,请在 experimental.fonts 对象中,配置至少一个字体:

astro.config.mjs
import { defineConfig, fontProviders } from "astro/config";
export default defineConfig({
experimental: {
fonts: [{
provider: fontProviders.google(),
name: "Roboto",
cssVariable: "--font-roboto"
}]
}
});

接着,在 <head> 部分,添加 <Font /> 组件并运用于全站样式:

src/components/Head.astro
---
import { Font } from 'astro:assets';
---
<Font cssVariable='--font-roboto' preload />
<style>
body {
font-family: var(--font-roboto);
}
</style>
  1. experimental.fonts 接受以数组类型传入字体对象。每个字体,必须指定 provider(提供商)、name(字体名称)并定义 cssVariable 来指向所使用的字体。

    下面示例配置了 Google Fonts 中的 “Roboto” 字体

    astro.config.mjs
    import { defineConfig, fontProviders } from "astro/config";
    export default defineConfig({
    experimental: {
    fonts: [{
    provider: fontProviders.google(),
    name: "Roboto",
    cssVariable: "--font-roboto"
    }]
    }
    });

    更多可用的配置选项,例如定义 回退字体 和 下载哪种 weightsstylessubsets,将会基于你所选定的提供商有所不同。

    查看完整的 配置参考,以了解更多。

  2. 使用 <Font /> 组件来应用样式。该组件必须引入并添加到你页面的 <head> 部分。你需要提供字体的 cssVariable,也可以选择性的 输出预加载链接

    src/components/Head.astro
    ---
    import { Font } from 'astro:assets';
    ---
    <Font cssVariable="--font-roboto" preload />

    这通常在组件中完成,而这些组件又嵌套在通用页面布局中,例如 Head.astro

    查看完整的 <Font> 组件参考,以获取更多信息。

    因为 <Font /> 组件会生成带有字体声明的 CSS,因此你可以使用 cssVariable 来引用该字体:

    <style>
    body {
    font-family: var(--font-roboto);
    }
    </style>

Astro 基于 unifont 提供商,导出了一些内置的字体提供商。你也可以创建自定义的 Astro 字体提供商

以下为内置支持的提供商:

要使用内置的远程提供商,请为你所选定的字体提供商选择合适的值,来配置 provider

provider: fontProviders.adobe({ id: 'your-id' })

可以通过在 Astro 配置文件中设置环境变量传递你的 Adobe 字体提供商 ID。

astro.config.mjs
import { defineConfig, fontProviders } from "astro/config";
export default defineConfig({
experimental: {
fonts: [
{
name: "Roboto",
cssVariable: "--font-roboto",
provider: fontProviders.google(),
// 默认包含项:
// weights: [400] ,
// styles: ["normal", "italics"],
// subsets: ["latin"],
// fallbacks: ["sans-serif"],
// formats: ["woff2"],
},
{
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: "local",
// 未指定字重和字体样式时,
// Astro 将会为每种 Variant 进行推测
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",
]
},
]
}
],
}
});

该组件输出样式标签,并且能够选择性的为给定字体输出预加载链接。

该组件必须导入并添加到你页面的 <head> 部分。这通常在组件中完成,而这些组件又嵌套在例如 Head.astro 这样的通用页面布局中,从而可以全局使用,但如有需要,它也能被导入到单个页面来使用。

利用该组件,你可以控制哪些字体被运用在哪些页面,以及哪些字体需要预加载。

示例类型: "--font-roboto" | "--font-comic-sans" | ...

在 Astro 配置中注册的 cssVariable

src/components/Head.astro
---
import { Font } from 'astro:assets';
---
<Font cssVariable="--font-roboto" />

类型: boolean | { weight?: string | number; style?: string; subset?: string }[]
默认值: false

是否输出 预加载链接

src/components/Head.astro
---
import { Font } from 'astro:assets';
---
<Font cssVariable="--font-roboto" preload />

通过 preload 指令,浏览器将在页面加载期间立即开始下载所有可能的字体的链接。

添加于: astro@5.15.0

你可能并不总是希望预加载所有字体链接,因为这可能会阻塞其他重要资源的加载,或者下载当前页面不需要的字体。

为了更精细地控制哪些字体文件会被预加载,你可以提供一个对象数组,用来描述需要预加载的字体特征组合,例如字体的 weight(字重)、style(样式)或 subset(子集)。

下面的示例只会预加载只会预加载 latin 子集中,字重为 400 或样式为 normal 的字体文件:

src/components/Head.astro
---
import { Font } from 'astro:assets';
---
<Font
cssVariable="--font-roboto"
preload={[
{ subset: 'latin', style: 'normal' },
{ weight: '400' },
]}
/>

对于可变字重(variable weight)的字体文件,只要其字重范围中包含了被请求的字重,就会被预加载。例如,字重范围为 100 900 的字体文件,在 preload 对象中指定了 400 时,就会被包含在内。

getFontData() 函数旨在通过编程方式获取更底层的字体数据,例如在 API 路由 中使用,或用于生成自定义的元标签。

类型: (cssVariable: CssVariable) => FontData[]

添加于: astro@5.14.0

返回与指定 cssVariable 对应的 FontData 对象数组,每个对象包含 srcweightstyle 属性。

以下示例演示了在使用 satori 生成 OpenGraph 图片时,如何通过 getFontData() 从 URL 获取字体缓冲区数据:

src/pages/og.png.ts
import type{ APIRoute } from "astro"
import { getFontData } from "astro:assets"
import satori from "satori"
export const GET: APIRoute = (context) => {
const data = getFontData("--font-roboto")
const svg = await satori(
<div style={{ color: "black" }}>hello, world</div>,
{
width: 600,
height: 400,
fonts: [
{
name: "Roboto",
data: await fetch(new URL(data[0].src[0].url, context.url.origin)).then(res => res.arrayBuffer()),
weight: 400,
style: "normal",
},
],
},
)
// ...
}

所有的字体属性都必须在 Astro 配置文件中进行配置。有些属性对于远程和本地字体来说是通用的,而其他属性则根据你选择的字体提供商提供。

下列属性对于远程和本地字体来说均可用。providernamecssVariable 是必要属性。

astro.config.mjs
import { defineConfig, fontProviders } from "astro/config";
export default defineConfig({
experimental: {
fonts: [{
provider: fontProviders.google(),
name: "Roboto",
cssVariable: "--font-roboto"
}]
}
});

类型: FontProvider | "local"

字体文件的来源。你可以使用 内置提供商 来编写你自己的 自定义提供商,或者是通过将该项设置为 "local" 来使用本地字体文件:

astro.config.mjs
import { defineConfig, fontProviders } from "astro/config";
export default defineConfig({
experimental: {
fonts: [{
provider: fontProviders.google(),
name: "Roboto",
cssVariable: "--font-roboto"
}]
}
});

类型: string

字体名称,由字体提供商所确定:

name: "Roboto"

类型: string

一个有效的、由你选定的、以 CSS 变量形式的 ident(例如:通常以 -- 开头):

cssVariable: "--font-roboto"

类型: string[]
默认值: ["sans-serif"]

一个包含字体的数组,用以在选定字体不可用时进行加载。回退字体将会按照列表顺序被选用。第一个可用的字体将会被使用:

fallbacks: ["CustomFont", "serif"]

要彻底禁用回退字体,可配置一个空数组:

fallbacks: []

指定至少一个与你字体外观预期相匹配的 通用字体族名,Astro 将会尝试使用字体度量(font metrics)来生成 优化后的字体回退。要禁用这种优化过程,可将 optimizedFallbacks 设置为 false。

类型: boolean
默认值: true

当生成回退字体时,是否启用 Astro 默认的优化过程。你可以禁用该默认的优化过程,以实现对 fallbacks 生成过程的完全掌控:

optimizedFallbacks: false

远程字体可使用进一步配置选项来进行配置。通过设置这些选项来自定义这些由 字体提供商 所加载的数据,例如仅下载特定的字重和字体样式。如需更精细的控制,可参考详细远程字体配置

每个字体提供商负责处理这些配置项,因此以下属性的可用性和支持情况可能因提供商而异。

类型: (number | string)[]
默认值: [400]

一个包含 字重 的数组。若未在配置中指定该属性,则默认仅包含字重 400,以避免下载未使用的字体文件。如需使用其他字重,必须显式声明此属性:

weights: [200, "400", "bold"]

如果所关联的字体为 可变字体,那么你可以指定字重的范围:

weights: ["100 900"]

类型: ("normal" | "italic" | "oblique")[]
默认值: ["normal", "italic"]

一个包含 字体样式 的数组:

styles: ["normal", "oblique"]

类型: string[]
默认值: ["latin"]

定义 字体子集,用以预加载。

subsets: ["latin"]

类型: ("woff2" | "woff" | "otf" | "ttf" | "eot")[]
默认值: ["woff2"]

添加于: astro@5.16.7

一个包含 字体格式 的数组:

formats: ["woff2", "woff"]

类型: "auto" | "block" | "swap" | "fallback" | "optional"
默认值: "swap"

定义 字体显示方式,根据字体文件下载和准备就绪的时间,控制渲染行为:

display: "block"

类型: string[]
默认值: undefined

该属性用于根据指定的 Unicode 字符范围 控制字体的按需下载和使用。若页面中存在字符匹配该属性的范围,那么浏览器将下载字体文件,且页面中所有字符均可使用该字体。如需为单个字体配置预装的字体子集,可参阅 subset 属性用作替代。

该属性在多语言本地化场景中尤为实用,当网站的特定部分使用其他字母时,会通过显示单独的字体来避免不必要的字体下载。例如,某网站同时提供英文和日文版本时,若当前的英文页面中不存在 unicodeRange 定义的日文字符时,浏览器将完全跳过对日文字体的下载。

unicodeRange: ["U+26"]

类型: string
默认值: undefined

字体拉伸

stretch: "condensed"

类型: string
默认值: undefined

用以控制 字体排印特性(例如:连字,小型大写字母,或是花体字):

featureSettings: "'smcp' 2"

类型: string
默认值: undefined

字体的 可变设置

variationSettings: "'xhgt' 0.7"

类型: LocalFontFamily["variants"]

当使用本地字体文件时,variants 属性是必要的。每个 Variant 就相当于一个 @font-face 声明,并且需要对应的 weightstylesrc 值。

此外,可以在每个 Variant 中指定 远程字体的某些其他属性

astro.config.mjs
import { defineConfig } from "astro/config";
export default defineConfig({
experimental: {
fonts: [{
provider: "local",
name: "Custom",
cssVariable: "--font-custom",
variants: [
{
weight: 400,
style: "normal",
src: ["./src/assets/fonts/custom-400.woff2"]
},
{
weight: 700,
style: "normal",
src: ["./src/assets/fonts/custom-700.woff2"]
}
// ...
]
}]
}
});

类型: number | string
默认值: undefined

字重

weight: 200

如果所关联的字体为 可变字体,那么你可以指定字重的范围:

weight: "100 900"

当该值未被设置时,默认情况下,Astro 将会尝试根据第一个 source 来推断该值。

类型: "normal" | "italic" | "oblique"
默认值: undefined

字体样式

style: "normal"

当该值未被设置时,默认情况下,Astro 将会尝试根据第一个 source 来推断该值。

类型: (string | URL | { url: string | URL; tech?: string })[]

字体 来源。它可以是一条相对于根目录的相对路径,也可以来自于包的导入或是一个 URL。如果你是通过集成来注入本地字体,则 URL 特别有用:

src: ["./src/assets/fonts/MyFont.woff2", "./src/assets/fonts/MyFont.woff"]

你也可以通过提供对象,来指定一个 tech

src: [{ url:"./src/assets/fonts/MyFont.woff2", tech: "color-COLRv1" }]

下列来自于远程字体的可用选项,也可用于本地字体的 Variant 中:

astro.config.mjs
import { defineConfig } from "astro/config";
export default defineConfig({
experimental: {
fonts: [{
provider: "local",
name: "Custom",
cssVariable: "--font-custom",
variants: [
{
weight: 400,
style: "normal",
src: ["./src/assets/fonts/custom-400.woff2"],
display: "block"
}
]
}]
}
});

添加于: astro@5.15.6

一个字体族(font family)通常由多种属性组合定义而成,例如字重(weights)和样式(styles)(例如:weights: [500, 600]styles: ["normal", "bold"])。但有时你可能只想下载这些属性的某些组合。

为了更精确地控制需要下载哪些字体文件,你可以 多次声明同一个字体(即具有相同的 cssVariablenameprovider 属性),但使用不同的属性组合。Astro 会合并这些结果,并且只下载所需的文件。例如,你可以仅下载常规样式的 500600 字重,但只下载斜体的 500 字重:

astro.config.mjs
import { defineConfig, fontProviders } from "astro/config"
export default defineConfig({
experimental: {
fonts: [
{
name: "Roboto",
cssVariable: "--roboto",
provider: fontProviders.google(),
weights: [500, 600],
styles: ["normal"]
},
{
name: "Roboto",
cssVariable: "--roboto",
provider: fontProviders.google(),
weights: [500],
styles: ["italic"]
}
]
}
})

如果你不想局限于使用任一的 内置提供商(例如,你想使用第三方 unifont 提供商,或为私有注册表构建某些内容),那么你便可以创建自己的字体提供商。

实现自定义字体提供商的推荐方式是导出一个函数,该函数接收配置作为参数,并返回一个 FontProvider 对象

实验性字体 API 允许你以统一的方式访问字体。每个字体族需通过一个 Astro 字体提供商来获取对应的字型(font face)。

FontProvider 是一个对象,包含必需的 nameresolveFont() 属性,同时还可以选择性地提供 configinit() 以及 listFonts() 属性。

类型: string

提供商的唯一名称,用于日志记录和标识。

类型: (options: ResolveFontOptions) => Awaitable<{ fonts: FontFaceData[] } | undefined>

用于检索并返回基于给定选项的字型数据。

类型: Record<string, any>
默认值: undefined

一个可序列化的对象,用于标识。

类型: (context: FontProviderInitContext) => Awaitable<void>
默认值: undefined

可选的回调,用于执行任何初始化逻辑。其上下文包含一个 storage 对象,便于缓存。

类型: () => Awaitable<string[] | undefined>
默认值: undefined

可选的回调,用于返回可用字体名称列表。

下面的示例定义了一个用于私有注册表的字体提供商:

font-provider.ts
import type { FontProvider } from "astro";
import { retrieveFonts, type Fonts } from "./utils.js",
interface Config {
token: string;
}
export function registryFontProvider(config: Config): FontProvider {
let data: Fonts = {}
return {
name: "registry",
config,
init: async () => {
data = await retrieveFonts(token);
},
listFonts: () => {
return Object.keys(data);
},
resolveFont: ({ familyName, ...options }) => {
const fonts = data[familyName];
if (fonts) {
return { fonts };
}
return undefined;
},
};
}

你可以在 Astro 配置中注册此字体提供商:

astro.config.ts
import { defineConfig } from "astro/config";
import { registryFontProvider } from "./font-provider";
export default defineConfig({
experimental: {
fonts: [{
provider: registryFontProvider({
token: "..."
}),
name: "Custom",
cssVariable: "--font-custom"
}]
}
});

你可以定义一个 Astro 字体提供商,底层使用 unifont 提供商:

font-provider.ts
import type { FontProvider } from "astro";
import type { InitializedProvider } from 'unifont';
import { acmeProvider, type AcmeOptions } from '@acme/unifont-provider'
function acmeFontProvider(config?: AcmeOptions): FontProvider {
const provider = acmeProvider(config);
let initializedProvider: InitializedProvider | undefined;
return {
name: provider._name,
config,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
},
};
}

你可以在 Astro 配置中注册此字体提供商:

astro.config.ts
import { defineConfig } from "astro/config";
import { acmeFontProvider } from "./font-provider";
export default defineConfig({
experimental: {
fonts: [{
provider: acmeFontProvider({/* ... */}),
name: "Custom",
cssVariable: "--font-custom"
}]
}
});

字体 API 的缓存实现,旨在保证开发环境的实用性和生产环境的高效率。在构建阶段,字体文件会被拷贝到 _astro/fonts 输出目录,因此他们可以从静态资源的 HTTP 缓存中受益(通常为一年时间)。

想清理开发环境中的缓存,可删除 .astro/fonts 目录。想清理构建时产生的缓存,可删除 node_modules/.astro/fonts 目录。

有关此实验性 API 的全部详细信息或需提供反馈,请参见 字体 RFC

贡献 社区 赞助