I'm using NextJS along with Tailwind CSS.
In my app, users can select a theme that includes different color schemes along with a pre-selected list of fonts. They can choose a font that they will like for the app.
These are only Google Fonts.
I'm not sure what's the best way to load a font based on the font name received from the database. I can load the data from the database
in serverSideProps
, but then how can I load the font before render so that there is no screen flicker. Can you please help?
UPDATE
As of now, I've done the following:
In tailwind.config.js
, I've extended the theme with different fonts that are available.
theme: { fontFamily: { inter: ['Inter', 'sans-serif'], cal: ["Cal Sans", "Inter", "sans-serif"], arima:['Arima Madurai','cursive'], opensans:['Open Sans', 'sans-serif'], } }
I've created a stylesheet for each font, which is stored in public folder at this location:
/fonts/opensans/stylesheet.css
/fonts/cal/stylesheet.css
/fonts/inter/stylesheet.css
/fonts/arima/stylesheet.css
These stylesheets contain the font. An example below:
@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
), I load the user's preferences using serverSideProps
and pass it to a Layout
component. This layout component has the head
which is created through next/head
. Let's call the font prop received from server as themeFont
. Let's say the user's preference is Cal Sans
, and the user's preference is stored in the database as value cal
. So, themeFont
value will be cal
.
In the head, I load the related stylesheet as follows:
<Head>
<link rel="stylesheet" href={`/fonts/${themeFont}/stylesheet.css`}></link>
</Head>
/fonts/cal/stylesheet.css
and the required font. No other font is loaded. Then I can use it in my components with font-cal
because it has been defined in tailwind.config.css
It works fine. I still see a flicker, maybe because of the font-display:swap
, or maybe it is because of some other reason. But I still feel this is not the optimal solution and this could be done in a better way.
Looking for help in this.
You are in the right direction, you should use getServerSideProps
to set the desired font in the <link>
tag. But you should add rel="preload"
attribute to load fonts first and then you can place link for your css.
<link rel="preload" href="/fonts/theme-font.woff2" as="font" type="font/woff2" ></link>
The preload value of the element's rel attribute lets you declare fetch requests in the HTML's, specifying resources that your page will need very soon, which you want to start loading early in the page lifecycle, before browsers' main rendering machinery kicks in.
Then to avoid flicker use fallback
value for font-display
property, it will hide the text for about 100ms and, if the font has not yet been downloaded, will use the fallback text.
@font-face {
font-family: "Cal Sans";
font-display: fallback;
src: url("CalSans-SemiBold.woff2") format("woff2"),
}
You can use the following values for font-display
for different strategy:
As an alternative solution, you can embed your fonts inside your css styles:
@font-face {
font-family: "Cal Sans";
font-display: fallback;
src: url(PASTE-BASE64-HERE) format('woff2')
}
Check this demo as a reference and there you can convert the woff2 file to base64.
Two ideas:
https://fontsource.org/docs/getting-started
Then you should be able to dynamically import the corresponding font as soon as you know what the font is. I don't know if the font would flicker here.
await import `@fontsource/${fontName}`;
This assumes you know fontName
will be a valid Google Font name, or you'd need a try
/ catch
for it.
getServerSideProps
, then use a custom <Head>
element to point to the corresponding CSS file on fonts.googleapis.com
and load that as part of the <Head>
before other content renders (or at least as it's in the process of doing so.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.