Step 1 - Creating a Next.js application
I just like all my development folders to be on Desktop so i do cd Desktop
cd Desktop
npx create-next-app
//Running this script on the folder you want to store the project folder
* Will ask you whats your project name? projectName
/*
Enter the project name and it will create a folder with that name along
with all the neccessary files
*/
Step 2 - Adding custom fonts (local)
📁 pages
📁 public
⠀⠀⠀📁 fonts
⠀⠀⠀⠀⠀⠀fontName-style.woff
Step 3 - Preloading these fonts in _document.js.
Create _document.js file if you haven’t already and add the following code it preloads the font inside the Head.
If you are not using styled-component you should remove everything starting from static till render()
_document.js
import Document, {Html, Head, Main, NextScript } from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
//--------------For styled-components only------------//
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
//---------------------------------------------------//
render() {
return (
<Html lang="en">
<Head>
<link
rel="preload"
href="/fonts/ProximaNova-Bold.woff"
as="font"
type="font/woff"
crossOrigin=""
/>
<link
rel="preload"
href="/fonts/ProximaNova-Regular.woff"
as="font"
type="font/woff"
crossOrigin=""
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
- All that is important here is that tag inside Head.
-
PS: Html =/= html
this 'Html" is common one for all the pages.
It is recommended that for using title and meta you do it inside a specific page's
tag.
Also if you are not sure what all the code outside render means, i am using styled-component as my preferred choice for styling so that code is just for getting styled-components to work on Server side. Check out this blog to understand styled-components in Next.js for more details.
Extra:
Short answer: Yes, You can use both. They serve different purpose and can be used in the same application.
According to nextjs website:
Next.js uses the App component to initialize pages.To override, create the ./pages/_app.js file and override the App class
and
Pages in Next.js skip the definition of the surrounding document's markup. For example, you never include ,
, etc. To override that default behavior, you must create a file at ./pages/_document.js, where you can extend the Document class.
Note: _document.js
is only rendered on the server side and not on the client side. so event handlers like onClick
is not going to work.
Step 4 - Declaring them globally
(again this is using style-components. Read more
create a _app.js file in your pages folder if its not already and add the . following:
import { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
@font-face {
font-family: 'ProximaNova-Regular';
src: url('/fonts/ProximaNova-Regular.woff') format('woff');
font-style: normal;
font-weight: 400;
font-display: swap;
}
@font-face {
font-family: 'ProximaNova-Bold';
src: url('/fonts/ProximaNova-Bold.woff') format('woff');
font-style: bold;
font-weight: 700;
font-display: swap;
}
`;
function MyApp({ Component, pageProps }) {
return (
<>
<GlobalStyle />
<Component {...pageProps} />
</>
);
}
export default MyApp
Whats happening here?
In my global styles i am declaring @font-face and the source of each face is pointing to the url of the font-faces inside the font folder we just created.
- Take care using @font-face, each font-family name is different and in accordance to the actual font file.
- font-display is kept to swap.
Now here if you are interested in knowing what font display actually does Check out this article on CSS-tricks also this is helpful in understanding FOUT and FINT which you can read more about over here.
Thats it! Test it.
Now you add the following code inside index.js
index.js:
import Head from 'next/head'
// import styles from '../styles/Home.module.css'
import styled from 'styled-components';
const Test1 = styled.p`
font-size: 40px;
font-family: 'ProximaNova-Regular';
color: #00688B;
`;
const Test2 = styled.p`
font-size: 40px;
font-family: 'ProximaNova-Bold';
color: #00688B;
`;
export default function Home() {
return (
<div>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<Test1>Test1</Test1>
<Test2>Test2</Test2>
</main>
</div>
)
Once this is added go to your terminal inside your folder and run:
$ yarn dev
// $ just mean run it inside your bash terminal you just need to copy "yarn dev"
Once this is done go to https://localhost.3000 and see your next.js app running.
Helpful Debugging:
Check for Safari developer tools and Google Chrome developer tools:
If you see a fonts folder in there and inside them if you can see font file. That most probably means your fontfiles have been successfully be served and it is good to go.
Important Links
-
Keep looking at this open source repository of Next.js actual site. https://github.com/vercel/next-site
Specifically look at how they have declared fonts inside /styles/fonts.js and are calling it inside _app.js
If you observe closely there might be flashing of fonts happening in your project - Look more into FOUT (Flash of Unstyled Text) and FOIT (Flash of Invisible Text) https://leerob.io/blog/things-ive-learned-building-nextjs-apps
I even found this repository that uses the same libraries (next + styled components) you can have a look at it for any updates.
Some mistakes i made:
Before trying anything else i used a library called next-fonts and they had created a next.config.js file. However at the time of speaking the library is deprecated and you can directly use fonts without any library.
This file uses two libraries:
- next-fonts
- @zeit/next-css
const withCss = require("@zeit/next-css");
const withFonts = require("next-fonts");
module.exports = withFonts(
withCss({
webpack: (config, { isServer }) => {
if (isServer) {
const antStyles = /antd\/.*?\/style\/css.*?/;
const origExternals = [...config.externals];
config.externals = [
(context, request, callback) => {
if (request.match(antStyles)) return callback();
if (typeof origExternals[0] === "function") {
origExternals[0](context, request, callback);
} else {
callback();
}
},
...(typeof origExternals[0] === "function" ? [] : origExternals)
];
config.module.rules.unshift({
test: antStyles,
use: "null-loader"
});
}
return config;
}
})
);
or just install @zeit/next-css
const withCSS = require('@zeit/next-css')
module.exports = withCSS({
cssLoaderOptions: {
url: false
}
})
The point of this file is to stop css modules to render and prevent any conflicts. But i personally haven't used it for my own site.
Links that helped me make this possible:
https://codeconqueror.com/blog/using-google-fonts-with-next-js
https://leerob.io/blog/things-ive-learned-building-nextjs-apps
https://github.com/styled-components/styled-components/issues/3224
Top comments (1)
That was useful. But the font-face should use only for custom fonts or could be use for google font also?