NextJS:从数据库加载字体

4
我正在使用NextJS和Tailwind CSS。
在我的应用中,用户可以选择包括不同颜色方案和预先选定字体列表的主题。他们可以选择喜欢的应用程序字体。这些仅限于Google字体。
我不确定基于从数据库接收到的字体名称加载字体的最佳方法是什么。我可以在serverSideProps中从数据库中加载数据,但是如何在渲染之前加载字体,以便没有屏幕闪烁呢? 请帮忙一下?
更新:
目前为止,我已经完成了以下工作:
1. 在tailwind.config.js中,我扩展了可用的不同字体主题。 ``` theme: { fontFamily: { inter: ['Inter', 'sans-serif'], cal: ["Cal Sans", "Inter", "sans-serif"], arima:['Arima Madurai','cursive'], opensans:['Open Sans', 'sans-serif'], } } ```
2. 我为每种字体创建了一个样式表,存储在公共文件夹中的以下位置: - /fonts/opensans/stylesheet.css - /fonts/cal/stylesheet.css - /fonts/inter/stylesheet.css - /fonts/arima/stylesheet.css
这些样式表包含字体。以下是一个样例:
@font-face {
  font-family: "Cal Sans";
  src: url("CalSans-SemiBold.woff2") format("woff2"),
    url("CalSans-SemiBold.woff") format("woff");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

在页面上(例如pages/index.js),我使用serverSideProps加载用户的偏好设置,并将其传递给Layout组件。此布局组件具有通过next/head创建的head。让我们将从服务器接收到的字体属性称为themeFont
假设用户的偏好是Cal Sans,并且用户的偏好以值cal的形式存储在数据库中。因此,themeFont的值将为cal
在头部,我按以下方式加载相关样式表:
<Head>
  <link rel="stylesheet" href={`/fonts/${themeFont}/stylesheet.css`}></link>
</Head>
  1. 这将加载/fonts/cal/stylesheet.css和所需的字体,不会加载其他字体。然后我可以在我的组件中使用font-cal,因为它已经在tailwind.config.css中定义。

这个方法可行,但仍然会出现闪烁,可能是因为font-display:swap,也可能是由于其他原因。但我仍然觉得这不是最优解,可能有更好的方法。

寻求帮助。

2个回答

5

解决方案1

您已走在正确的方向上,应该使用getServerSideProps<link>标签中设置所需字体。但是您应该添加rel="preload"属性来首先加载字体,然后才能放置css链接。

<link rel="preload" href="/fonts/theme-font.woff2" as="font" type="font/woff2" ></link>

在HTML的元素的rel属性中使用preload值,可以声明资源的获取请求,指定页面很快就需要的资源,在浏览器的主要渲染机制启动之前尽早开始加载。

然后为了避免闪烁,在font-display属性中使用fallback值,它将在大约100毫秒后隐藏文本,并且如果字体还没有被下载,则使用备用文本。

@font-face {
  font-family: "Cal Sans";
  font-display: fallback;
  src: url("CalSans-SemiBold.woff2") format("woff2"),
}

您可以使用以下值来设置不同的font-display策略:
  • auto(默认):允许浏览器使用其默认的加载方法,通常类似于块值。
  • block:指示浏览器在完全下载字体之前短暂隐藏文本。更准确地说,浏览器将用一个看不见的占位符绘制文本,然后在自定义字体面加载后立即将其替换。这也被称为“闪烁的不可见文本”或FOIT。
  • swap:指示浏览器使用回退字体显示文本,直到自定义字体完全下载。这也被称为“未样式化文本的闪烁”或FOUT。
  • fallback:作为自动和交换值之间的妥协。浏览器将隐藏文本约100毫秒,并在字体尚未下载时使用回退文本。它会在下载后交换到新字体,但仅在短暂的交换期间内(可能是3秒)。
  • optional:与fallback类似,此值告诉浏览器最初隐藏文本,然后转换为回退字体,直到可用自定义字体。然而,此值还允许浏览器确定是否使用自定义字体,使用用户的连接速度作为决定因素,其中较慢的连接不太可能接收到自定义字体。

解决方案2

作为另一种解决方案,您可以在CSS样式中嵌入字体:
@font-face {
  font-family: "Cal Sans";
  font-display: fallback;
  src: url(PASTE-BASE64-HERE) format('woff2')
}

可以参考 此演示,你可以将woff2文件转换为base64格式。


2
两个想法:
1. Fontsources维护了完整的Google Fonts存储库作为NPM包。只要安装了相应的NPM包,您就应该能够动态导入所需的字体。
2. 然后,只要知道字体是什么,您就应该能够动态导入相应的字体。我不知道这里是否会出现闪烁的情况。
参考链接:https://fontsource.org/docs/getting-started
await import `@fontsource/${fontName}`;

假设您知道fontName是有效的Google字体名称,或者您需要对其进行try/catch


  1. 另一种方法是在服务器上获取字体信息(如果您正在使用Next.js,则可以使用getServerSideProps),然后使用自定义的<Head>元素指向fonts.googleapis.com上相应的CSS文件,并在渲染其他内容之前(或至少在渲染过程中)将其作为<Head>的一部分加载。

谢谢,我会尝试这些解决方案。 - asanas
我尝试了这些选项,但它们会导致闪烁。我需要一些更高级别的解决方案。谢谢你的帮助。 - asanas
第二种方法(使用getServerSideProps)应该可以胜任,只要您从服务器获取信息并将它们加载到_app.page.js的头部即可。我认为您无法获得比getServerSideProps更根本的解决方案。 - Berci

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接