using google fonts in nextjs with sass, css and semantic ui react - css

I have a next.config.js file that has the following configuration:
const withSass = require('#zeit/next-sass');
const withCss = require('#zeit/next-css');
module.exports = withSass(withCss({
webpack (config) {
config.module.rules.push({
test: /\.(png|svg|eot|otf|ttf|woff|woff2)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000,
publicPath: './',
outputPath: 'static/',
name: '[name].[ext]'
}
}
})
return config
}
}));
This is great because it runs my semantic ui css files.
Now I have a problem. I can't seem to successfully import any google font url. I tried downloading the ttf file into my file path and tried to reference it with the #import scss function. However I get a GET http://localhost:3000/fonts/Cabin/Cabin-Regular.ttf net::ERR_ABORTED 404 (Not Found) error
Here is what I'm trying to do with google font:
#font-face {
font-family: 'Cabin';
src: url('/fonts/Cabin/Cabin-Regular.ttf') format('truetype');
}
$font-size: 100px;
.example {
font-size: $font-size;
font-family: 'Cabin', sans-serif;
}
I have also downloaded the relevant npm dependencies:
"#zeit/next-css": "^1.0.1",
"#zeit/next-sass": "^1.0.1",
"file-loader": "^2.0.0",
"next": "^7.0.2",
"node-sass": "^4.9.4",
"react": "^16.6.0",
"react-dom": "^16.6.0",
"semantic-ui-css": "^2.4.1",
"semantic-ui-react": "^0.83.0",
"url-loader": "^1.1.2"

I know in Next.js 9.3, you can copy the #import statement from Google Fonts:
#import url('https://fonts.googleapis.com/css2?family=Jost&display=swap');
and place this in some css file, lets say styles/fonts.css like so:
#import url('https://fonts.googleapis.com/css2?family=Jost&display=swap');
.jost {
font-family: 'Jost', sans-serif;
}
Then import that inside of your global _app.js file like so:
import `../styles/fonts.css`
Now you have global access to that class containing the Google Font in every next.js page

I think the other solution is to use fonts directly from Google. Just customize _app.js file and add a <link rel="stylesheet" /> in the <Head />
Example _app.js
import React from 'react';
import App, { Container } from 'next/app';
import Head from 'next/head';
export default class MyApp extends App {
static async getInitialProps({ Component, router, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps };
}
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<Head>
<link
href="https://fonts.googleapis.com/css?family=Cabin"
rel="stylesheet"
key="google-font-cabin"
/>
</Head>
<Component {...pageProps} />
<style global jsx>{`
body {
font-family: 'Cabin', sans-serif;
}
`}</style>
</Container>
);
}
}

class NextApp extends App {
render() {
const { Component } = this.props
return (
<React.Fragment>
<Component {...pageProps} />
<style jsx="true" global>{`
#import url('https://fonts.googleapis.com/css?family=Roboto');
body {
margin: 0;
font-family: 'Roboto', sans-serif;
}
`}</style>
</React.Fragment>
</Provider>
</Container>
)
}
}
Including the font url from Google Fonts in styled-jsx worked for me.

As per the latest docs you can now add global css by updating the _app.js file and importing your css style. Follow the steps below
Create custom _app.js file in the pages directory by following the docs.
Add your styles.css file to the pages directory.
Include the styles as below
// _app.js
// Import styles
import './styles.css'
// Function to create custom app
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
// Export app
export default MyApp
and done. These styles styles.css will apply to all pages and components in your application. Due to the global nature of stylesheets, and to avoid conflicts, you may only import them inside _app.js.

I had to put the files into the static folder for it to work, must've been a specific setup for rendering images and fonts in nextjs

If you are using a functional custom app, then you can add google fonts or any cdn linked fonts to the head of the whole app as follows:
import Head from 'next/head';
// Custom app as a functional component
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<link
href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght#300;400;600;700&display=swap" rel="stylesheet"/>
</Head>
<Component {...pageProps}/>
</>
)
}
MyApp.getInitialProps = async ({ Component, ctx }) => {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps };
};
// Export app
export default MyApp
now you can use css to apply the font family to the body element to get the font applied throughout the webiste, as shown below.
body {
font-family: 'Source Sans Pro', sans-serif;
}

Hhis is now how I am currently loading external fonts nonblocking. In _document.js head:
<script dangerouslySetInnerHTML={{__html: '</script><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" media="print" onload="this.media=\'all\'" /><script>' }} />
dangerouslySetInnerHTML and some script hacking to work around onload otherwise being removed from _document.js until this is resolved
source

Related

How to add custom local fonts to a Nextjs 13 Tailwind project?

I have downloaded a couple fonts (NOT GOOGLE FONTS) and I want to add and use them in my Nextjs 13 Tailwind project.
I've followed the Nextjs docs to try add a single font (I want to add multiple fonts but trying to get a single font added isn't working):
npm install #next/font
Add the downloaded font files to /pages/fonts
Add the fonts to /pages/_app.js
Add the fonts to tailwind.config.js
Use font in a component
Updated /pages/_app.js
import localFont from '#next/font/local'
const surt = localFont({
src: './fonts/Surt-Normal-Bold.woff2',
variable: '--font-surt-bold',
})
export default function MyApp({ Component, pageProps }) {
return (
<main className={surt.variable}>
<Component {...pageProps} />
</main>
)
}
Updated tailwind.config.js (Surt is a sans-serif font)
const { fontFamily } = require('tailwindcss/defaultTheme')
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {
fontFamily: {
sans: ['var(--font-surt)', ...fontFamily.sans],
},
},
},
plugins: [],
}
Updated About page
export default function About() {
return <div className="font-surt-bold">About</div>
}
What am I doing wrong and how would I update the code to add another font (eg Surt-Normal-Regular.woff2, Surt-Normal-Semibold-Italic.woff2)
After setting up TailwindCSS the way you did to use the font you should also add font-sans in the className you want to add the font to.
In this case, your _app.js should be
import localFont from '#next/font/local'
const surt = localFont({
src: './fonts/Surt-Normal-Bold.woff2',
variable: '--font-surt-bold',
})
export default function MyApp({ Component, pageProps }) {
return (
<main className={`${surt.variable} font-sans`}>
<Component {...pageProps} />
</main>
)
}
If you want to have different variants of the same font you can pass an array to the font src instead.
You can do it this way
const surt = localFont({
src: [
{
path: "./fonts/Surt-Normal-Regular.woff2",
weight: "400",
style: "normal",
},
{
path: "./fonts/Surt-Normal-Bold.woff2",
weight: "700",
style: "normal",
},
{
path: "./fonts/Surt-Normal-Black.woff2",
weight: "900",
style: "normal",
},
],
variable: "--font-surt-bold",
});
it is mentioned in the docs Here
Full credit goes to Lee Robinson and official v13 doc for my post.
The below will also help you with the new v13 /app directory.
1. Install next fonts
npm install #next/font
2. Download your fonts
In my case I downloaded the Poppins fonts and placed them in /public/fonts/
3. Link to your fonts file
As per docs you can edit your _app.js.
Link to your local fonts
assign a variable name
assign the class name to a parent html tag
In my case I am using the new app directory: /src/app/layout.tsx
import localFont from '#next/font/local'
const poppins = localFont({
src: [
{
path: '../../public/fonts/Poppins-Regular.ttf',
weight: '400'
},
{
path: '../../public/fonts/Poppins-Bold.ttf',
weight: '700'
}
],
variable: '--font-poppins'
})
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={`${poppins.variable} font-sans`}>
...
4. Reference in Tailwind config
As per docs you can now reference the new variable in your tailwind.config.js.
/** #type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/app/**/*.{js,ts,jsx,tsx}', // Note the addition of the `app` directory.
'./src/pages/**/*.{js,ts,jsx,tsx}',
'./src/components/**/*.{js,ts,jsx,tsx}'
],
theme: {
extend: {
fontFamily: {
sans: ['var(--font-poppins)']
}
}
},
plugins: []
}
If you console.log(surt),
const surt = localFont({
src: "../fonts/test.woff2",
variable: "--font-test-bold",
});
console.log("surt", surt);
you get this
// I used different font so values might be different
surt {
style: { fontFamily: "'__surt_899d56', '__surt_Fallback_899d56'" },
className: '__className_899d56',
variable: '__variable_899d56'
}
You dont need any configuration. All you have to do is apply this surt.className to an element and that font will be applied to all children.
<main className={surt.className}>
<Component {...pageProps} />
</main>
It works both for client components and app directory
how to apply this to any component in the project
I did the above configuration in _app.js and I did use any className or variable
import localFont from "#next/font/local";
const surt = localFont({
src: "../public/test.woff2",
variable: "--font-surt",
// I added this maybe fallback works but it did not
fallback: ["'Apple Color Emoji'"],
});
console.log("surt", surt);
export default function MyApp({ Component, pageProps }) {
return (
<main>
<Component {...pageProps} />
</main>
);
}
After you configure the tailwind.css the way you did, we should be able to use font-sans class anywhere in the project but no matter what I tried, tailwind does not inject it (it must be a bug). Workaround is like this. If you console the font, you will get this:
className: "__className_899d56"
style: {fontFamily: "'__surt_899d56', 'Apple Color Emoji','__surt_Fallback_899d56'"}
variable: "__variable_899d56"
I copied the style property from console (You could prop drill) and manually used it:
<p
className="'__className_899d56'"
style={{ fontFamily: "__surt_899d56" }}
>
with font testing
</p>

Google font loads very weirdly after the deployment to the vercel

I have deployed the next js app to the server using vercel. I have referenced the two google fonts in _document.js. While I am running the app locally both font load without any problem.
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document
{
static async getInitialProps(ctx)
{
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render()
{
return (
<Html>
<Head>
<link href="https://fonts.googleapis.com/css2?family=Crete+Round&family=Work+Sans:wght#500;600&display=swap" rel="stylesheet" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
index.js
import Head from "next/head";
import Script from "next/script";
import Banner from "../components/Banner";
import { fetchAPI } from "../lib/api";
import Articles from "../components/Articles";
export default function Home({ articles })
{
return (
<>
<Head>
<title>Life Sciencify - Explore the mystery of life with Science! </title>
</Head>
<Articles articles={articles} />
</>
);
}
export async function getServerSideProps()
{
const [articlesRes] = await Promise.all([
fetchAPI("/posts", { populate: ["cover", "category"] })
]);
console.log(articlesRes)
return {
props: {
articles: articlesRes.data
}
};
}
app.js
import Script from "next/script";
import "bootstrap/dist/css/bootstrap.css";
import "../styles/globals.css";
import { useEffect } from "react";
import Header from "../components/Header";
import SearchBlock from "../components/SearchBlock";
import Footer from "../components/Footer";
function MyApp({ Component, pageProps })
{
useEffect(() =>
{
import("bootstrap/dist/js/bootstrap");
}, []);
return (
<>
<Component {...pageProps} />
</>
);
}
export default MyApp;
After the deployment it is showing the weird behavior.
Initially When I am in the home page the page doesn't load any font.
Now, when I click the link Post1 or Post 2, it will be redirected to the detail page.
at first font is not loaded in this page too.
Now, after the page refresh the font gets loaded.
Now, when I go to the back page in the browser, the home page will have the font loaded. But again when the page is refreshed the font will be gone.
What is the causing the weird behavior?
I am running the application in the next js version of "12.1.6".
Referenced:
google-font-display
font-optimization
In the _document.js i used two google fonts separately and it is working now.
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document
{
static async getInitialProps(ctx)
{
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render()
{
return (
<Html>
<Head>
<link href="https://fonts.googleapis.com/css2?family=Work+Sans:wght#500;600&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Crete+Round&display=swap" rel="stylesheet" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
and in index.js, change server side rendering to static props:
export async function getStaticProps()
{
const [articlesRes] = await Promise.all([
fetchAPI("/posts", { populate: ["cover", "category"] })
]);
console.log(articlesRes)
return {
props: {
articles: articlesRes.data
}
};
}
After this changes I deployed to vercel it worked fine, again after some time i changes to getServerSideProps, it was not working. So, the culprit was getServerSideProps with google font.

Gloabl styles are not applying to other pages (Next.JS)?

I am new to NextJS and I am having an issue with getting global styles to apply to other pages. Am I using the global selector wrong? Below you can find my index.js, and add-article.js file including two images that show global styles only being applied to the homepage.
Below is my index.js file:
import Head from 'next/head';
import Navigation from '../components/navigation';
export default function ArticleList() {
return (
<div className='container'>
<Head>
<title>Article Vault</title>
<link rel='icon' href='/favicon.ico' />
</Head>
<div className='home-container'>
<Navigation />
<p>Home Page</p>
</div>
<style jsx>{``}</style>
<style jsx global>{`
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
sans-serif;
}
* {
box-sizing: border-box;
}
`}</style>
</div>
);
}
add-article.js
import Navigation from '../components/navigation';
const AddArticle = () => {
return (
<div className='add-article-container'>
<Navigation />
<p>Add Article Page</p>
</div>
);
};
export default AddArticle;
Home Page
Other Page
You have to make a custom _app.js to get this to work. Import your styles here instead of index.js and make wrapper. As an alternative can also make a global layout and pass your page components as childrens.
// import App from 'next/app' function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
// Only uncomment this method if you have blocking data requirements for
// every single page in your application. This disables the ability to
// perform automatic static optimization, causing every page in your app to
// be server-side rendered.
//
// MyApp.getInitialProps = async (appContext) => {
// // calls page's `getInitialProps` and fills `appProps.pageProps`
// const appProps = await App.getInitialProps(appContext);
//
// return { ...appProps }
// }
export default MyApp

PurgeCSS does not remove unused CSS from NextJS project

I'm trying to remove unused css from my NextJS project using PurgeCSS. However, I'm having difficulty getting the most basic integration of PurgeCSS into my project to work.
I'm using this documentation: https://www.purgecss.com/guides/next.
My next.config file looks like this:
// next.config.js
const withCss = require('#zeit/next-css')
const withPurgeCss = require('next-purgecss')
module.exports = withCss(withPurgeCss())
Here is my component:
import React from 'react'
import App from 'next/app'
export default class MyApp extends App {
render() {
const { Component, pageProps } = this.props
return (
<>
<style jsx global>{`
.purgecss-test {
color: red;
}
`}</style>
<Component {...pageProps} />
</>
)
}
}
When I do a global search in my code base for 'purgecss-test', I only get the one result that's in the component above, so I am expecting that style to be removed during the build. However, when my app builds and I navigate to the page and inspect the source, I can still see it there:
<style amp-custom="">.purgecss-test{color:red;}
Try customizing PostCSS instead as per this page (ignore tailwindcss): https://nextjs.org/learn/basics/assets-metadata-css/styling-tips
A bit simplified, install #fullhuman/postcss-purgecss and postcss-preset-env, then create a postcss.config.js file in the top-level directory and enter this in it:
module.exports = {
plugins: [
[
'#fullhuman/postcss-purgecss',
{
content: [
'./pages/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}'
],
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
}
],
'postcss-preset-env'
]
};

Import font into React application

I'm trying to use the Roboto font in my app and having tough time..
I did npm install --save typeface-roboto and added import 'typeface-roboto' to my React component. But still can't get my font to change.
I am trying to do like this :
const React = require('react')
import 'typeface-roboto'
class Example extends React.Component {
render() {
let styles = {
root: {
fontFamily: 'Roboto'
}
}
return (
<div style={styles.root}>
<p>
This text is still not Roboto ?!???!!1
</p>
</div>
)
}
}
module.exports = Example
Am I missing something? Looking for a simple way to do this without any external css file..
Try adding import 'typeface-roboto'; in root file i.e. index.js file.
In my case I added font-family to body element and it is worked.
import this code of line in your main css or scss whatever use use
#import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap');
this will work.
If you want to customize this then go to the google font and select font style font weight whatever you want.
Here i have selected font weight 400,300 and 700
If have not selected the font weight then you can not use other font weight
I had the same issue, couldn't get Roboto fonts for my components anyhow.
I used the webfontloader package.
yarn add webfontloader
or
npm install webfontloader --save
h
Once you do this, add the following code to your index.js or to the JS file which is an entry point to your application
import WebFont from 'webfontloader';
WebFont.load({
google: {
families: ['Titillium Web:300,400,700', 'sans-serif']
}
});
// rest of the index.js code
And now apply the font-family.
You simply just require('typeface-roboto') it.
const React = require('react')
require('typeface-roboto')
class Example extends React.Component {
render() {
let styles = {
root: {
fontFamily: 'Roboto'
}
}
return (
<div style={styles.root}>
<p>
This is now Roboto
</p>
</div>
)
}
}
// or here instead if you fancy
.root {
font-family: 'Roboto';
}
It involves several changes, assuming you want to use CSSinJS:
change style to className
You'll need some kind of library to apply styles.
With react-jss
import React from 'react';
import 'typeface-roboto';
import injectSheet from 'react-jss';
const styles = {
root: {
fontFamily: 'Roboto',
},
};
class Example extends React.Component {
render() {
return (
<div className={styles.root}>
This text is Roboto
</div>
)
}
}
const StyledExample = injectSheet(styles)(Example)
export default StyledExample;
Or with MaterialUI styles:
import React from 'react';
import 'typeface-roboto';
import { withStyles } from '#material-ui/core/styles';
const styles = theme => ({
root: {
fontFamily: 'Roboto',
},
});
function Example(props) {
const { classes } = props;
return (
<div className={classes.root}>
This text is Roboto
</div>
);
}
export default withStyles(styles)(Example);
Or, you could just do it the right way, via Dan's Answer
Or the Styled-Components way:
import styled from 'styled-components'
const ExampleStyled = styled.div`
#font-face {
font-family: 'Roboto';
src: local('Roboto'), url(fonts/Roboto.woff) format('woff');
}
`
const Example = () => (
<ExampleStyled>
This text is Roboto!
</ExampleStyled>
);
export default Example;

Resources