NextJS:从数据库加载字体
NextJS: Loading Font from Database
我正在使用 NextJS 和 Tailwind CSS。
在我的应用程序中,用户可以 select 包含不同配色方案以及预先 select 字体列表的主题。他们可以为应用程序选择他们喜欢的字体。
这些只是 Google 字体。
我不确定根据从数据库收到的字体名称加载字体的最佳方法是什么。我可以从 serverSideProps
中的 database
加载数据,但是我怎样才能在渲染之前加载字体以便没有屏幕闪烁。你能帮忙吗?
更新
截至目前,我已完成以下操作:
在 tailwind.config.js
中,我用可用的不同字体扩展了主题。
主题:{
字体系列: {
间:['Inter', 'sans-serif'],
cal: ["Cal Sans", "Inter", "sans-serif"],
华宇:['Arima Madurai','cursive'],
opensans:['Open Sans', 'sans-serif'],
}
}
我为每种字体创建了一个样式表,它存储在 public 文件夹中的这个位置:
/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>
- 这将加载
/fonts/cal/stylesheet.css
和所需的字体。没有加载其他字体。然后我可以在我的组件中使用它 font-cal
因为它已经在 tailwind.config.css
中定义
它工作正常。我仍然看到闪烁,可能是因为 font-display:swap
,也可能是其他原因。但我仍然觉得这不是最佳解决方案,可以通过更好的方式完成。
正在寻求帮助。
两个想法:
- Fontsources 维护着 Google 字体的完整存储库作为 NPM 包。你应该可以动态导入你需要的字体,只要安装了相应的npm包。
https://fontsource.org/docs/getting-started
那你知道是什么字体后应该就可以动态导入对应的字体了。不知道这里字体会不会闪烁
await import `@fontsource/${fontName}`;
这假设您知道 fontName
将是一个有效的 Google 字体名称,或者您需要一个 try
/catch
。
- 另一种方法是在服务器上获取字体信息(如果您正在使用 Next.js,您可以使用
getServerSideProps
来完成此操作,然后使用自定义 <Head>
元素指向到 fonts.googleapis.com
上相应的 CSS 文件,并在其他内容呈现之前将其作为 <Head>
的一部分加载(或者至少在呈现过程中。)
解决方案 1
你的方向是正确的,你应该使用getServerSideProps
在<link>
标签中设置想要的字体。但是你应该先添加 rel="preload"
属性来加载字体,然后你可以为你的 css.
放置 link
<link rel="preload" href="/fonts/theme-font.woff2" as="font" type="font/woff2" ></link>
元素的 rel 属性的预加载值允许您在 HTML 中声明获取请求,指定您的页面很快将需要的资源,您希望在页面生命周期的早期开始加载这些资源,在浏览器的主要渲染机制启动之前。
然后为避免闪烁使用 fallback
值 font-display
属性,它将隐藏文本约 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:作为 auto 和 swap 值之间的折衷。浏览器将隐藏文本约 100 毫秒,如果尚未下载字体,将使用后备文本。它会在下载后切换到新字体,但只会在很短的切换时间内(大概 3 秒)。
- optional:与回退一样,此值告诉浏览器最初隐藏文本,然后转换为回退字体,直到自定义字体可用为止。但是,此值还允许浏览器确定是否使用自定义字体,使用用户的连接速度作为决定因素,较慢的连接速度不太可能接收自定义字体。
解决方案 2
作为替代解决方案,您可以将字体嵌入 css 样式中:
@font-face {
font-family: "Cal Sans";
font-display: fallback;
src: url(PASTE-BASE64-HERE) format('woff2')
}
检查此 demo 作为参考,您可以在那里将 woff2 文件转换为 base64。
我正在使用 NextJS 和 Tailwind CSS。
在我的应用程序中,用户可以 select 包含不同配色方案以及预先 select 字体列表的主题。他们可以为应用程序选择他们喜欢的字体。
这些只是 Google 字体。
我不确定根据从数据库收到的字体名称加载字体的最佳方法是什么。我可以从 serverSideProps
中的 database
加载数据,但是我怎样才能在渲染之前加载字体以便没有屏幕闪烁。你能帮忙吗?
更新
截至目前,我已完成以下操作:
在
tailwind.config.js
中,我用可用的不同字体扩展了主题。主题:{ 字体系列: { 间:['Inter', 'sans-serif'], cal: ["Cal Sans", "Inter", "sans-serif"], 华宇:['Arima Madurai','cursive'], opensans:['Open Sans', 'sans-serif'], } }
我为每种字体创建了一个样式表,它存储在 public 文件夹中的这个位置:
/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>
- 这将加载
/fonts/cal/stylesheet.css
和所需的字体。没有加载其他字体。然后我可以在我的组件中使用它font-cal
因为它已经在tailwind.config.css
中定义
它工作正常。我仍然看到闪烁,可能是因为 font-display:swap
,也可能是其他原因。但我仍然觉得这不是最佳解决方案,可以通过更好的方式完成。
正在寻求帮助。
两个想法:
- Fontsources 维护着 Google 字体的完整存储库作为 NPM 包。你应该可以动态导入你需要的字体,只要安装了相应的npm包。
https://fontsource.org/docs/getting-started
那你知道是什么字体后应该就可以动态导入对应的字体了。不知道这里字体会不会闪烁
await import `@fontsource/${fontName}`;
这假设您知道 fontName
将是一个有效的 Google 字体名称,或者您需要一个 try
/catch
。
- 另一种方法是在服务器上获取字体信息(如果您正在使用 Next.js,您可以使用
getServerSideProps
来完成此操作,然后使用自定义<Head>
元素指向到fonts.googleapis.com
上相应的 CSS 文件,并在其他内容呈现之前将其作为<Head>
的一部分加载(或者至少在呈现过程中。)
解决方案 1
你的方向是正确的,你应该使用getServerSideProps
在<link>
标签中设置想要的字体。但是你应该先添加 rel="preload"
属性来加载字体,然后你可以为你的 css.
<link rel="preload" href="/fonts/theme-font.woff2" as="font" type="font/woff2" ></link>
元素的 rel 属性的预加载值允许您在 HTML 中声明获取请求,指定您的页面很快将需要的资源,您希望在页面生命周期的早期开始加载这些资源,在浏览器的主要渲染机制启动之前。
然后为避免闪烁使用 fallback
值 font-display
属性,它将隐藏文本约 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:作为 auto 和 swap 值之间的折衷。浏览器将隐藏文本约 100 毫秒,如果尚未下载字体,将使用后备文本。它会在下载后切换到新字体,但只会在很短的切换时间内(大概 3 秒)。
- optional:与回退一样,此值告诉浏览器最初隐藏文本,然后转换为回退字体,直到自定义字体可用为止。但是,此值还允许浏览器确定是否使用自定义字体,使用用户的连接速度作为决定因素,较慢的连接速度不太可能接收自定义字体。
解决方案 2
作为替代解决方案,您可以将字体嵌入 css 样式中:
@font-face {
font-family: "Cal Sans";
font-display: fallback;
src: url(PASTE-BASE64-HERE) format('woff2')
}
检查此 demo 作为参考,您可以在那里将 woff2 文件转换为 base64。