I'm trying to self-host webfonts using my NextJS app and having trouble. This is the URL browser tries to access these fonts:
localhost:3000/_next/static/css/fonts/Avenir.woff2
The actual path is:
_project_dir/static/fonts/Avenir.woff2
I tried including the link in the the _app.js, it does download the fonts, but the text remains unstyled.
<link rel="preload" as="font" href="/static/fonts/Avenir.woff2" type="font/woff2" crossorigin />
Here's my _app.js
:
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<link href="https://fonts.googleapis.com/css?family=Poppins:500,500i,600&display=swap" rel="stylesheet" />
<link rel="preload" as="font" href="/static/fonts/Avenir.woff2" type="font/woff2" crossorigin />
<link rel="preload" as="font" href="/static/fonts/AvenirHeavy.woff2" type="font/woff2" crossorigin />
<Head>
<title>Project</title>
</Head>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<Component pageContext={this.pageContext} {...pageProps} />
</PersistGate>
</Provider>
</Container>
);
}
}
My main.css
@font-face {
font-family: 'Avenir';
font-weight: 400;
font-style: normal;
font-display: swap;
src: url('fonts/Avenir.eot');
src: url('fonts/Avenir.eot?#iefix') format('embedded-opentype'), url('fonts/Avenir.woff2') format('woff2'),
url('fonts/Avenir.woff') format('woff'), url('fonts/Avenir.ttf') format('truetype');
}
@font-face {
font-family: 'Avenir';
font-weight: 500;
src: url('fonts/Avenir.eot');
src: url('fonts/Avenir.eot?#iefix') format('embedded-opentype'), url('fonts/Avenir.woff2') format('woff2'),
url('fonts/Avenir.woff') format('woff'), url('fonts/Avenir.ttf') format('truetype');
}
@font-face {
font-family: 'Avenir';
font-weight: 900;
src: url('fonts/AvenirHeavy.eot');
src: url('fonts/AvenirHeavy.eot?#iefix') format('embedded-opentype'), url('fonts/AvenirHeavy.woff2') format('woff2'),
url('fonts/AvenirHeavy.woff') format('woff'), url('fonts/AvenirHeavy.ttf') format('truetype');
}
And my next.config.js
:
webpack(config, options) {
config.module.rules.push({
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000,
},
},
});
return config;
},
To add a web font to your Next. js application, add the font to a Custom Document . Note that we don't recommend adding fonts with next/head , as this only applies the font to the particular page and won't work with a streaming architecture.
You don't need to any additional dependency to use fonts. Simply move your fonts to public/fonts
instead of static/fonts
.
Then to preload:
<link rel="preload" href="/fonts/Avenir.woff2" as="font" type="font/woff2" crossOrigin="anonymous" />
Remember to keep the beginning slash, otherwise it won't work. According to the official docs:
Files inside
public
can then be referenced by your code starting from the base URL (/
).
Also, in JSX, it's crossOrigin
not crossorigin
, and it expects a string
, not a Boolean
.
And in CSS/SCSS (add beginning slash to each src-url):
@font-face {
/* ... */
src: url('/fonts/Avenir.woff2') format('woff2');
/* ... */
}
Then remove the custom webpack configuration for font files. A downfall for this method is that the fonts will not be inlined as done by url-loader
. But I believe it is quite inefficient to inline all fonts anyway. (You've set a limit of 100000
. Almost every woff/woff2 font will be inlined.)
In newer versions of next I believe you can import
the WOFF2 file and use that in your CSS similar to this example for Gatsby. However, if you're not importing font files and instead placing them in the /static/fonts
directory as you explain you can avoid using the WebPack loader or a plugin like next-fonts by hard-coding the font paths in your static directory as suggested by Alex:
import React, { Fragment } from "react";
const WebFonts = () => (
<Fragment>
<style global jsx>{`
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-stretch: normal;
font-weight: 400;
font-display: fallback;
src: local("SourceSansPro Regular"), local("SourceSansPro-Regular"),
url(/static/fonts/SourceSansPro-Regular.woff2) format("woff2");
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
U+A720-A7FF;
}
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 600;
font-display: fallback;
src: local("SourceSansPro SemiBold"), local("SourceSansPro-SemiBold"),
url(/static/fonts/SourceSansPro-SemiBold.woff2) format("woff2");
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
U+A720-A7FF;
}
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 700;
font-display: fallback;
src: local("SourceSansPro SemiBold"), local("SourceSansPro-SemiBold"),
url(/static/fonts/SourceSansPro-Bold.woff2) format("woff2");
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
U+A720-A7FF;
}
`}</style>
</Fragment>
);
export default WebFonts;
And then importing that Component into your _document
override in NextJS. This will use fonts added to the NextJS static directory. Be sure to compress any TTF font downloads from Google Fonts using the woff2_compress
method provided by woff2 before serving them for better page speed. And if you're not seeing your local font downloads appearing in the Network waterfall in DevTools make sure you test by removing any local versions of those fonts or local
font face declarations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With