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

Viewed 15533

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"
7 Answers

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

  1. Create custom _app.js file in the pages directory by following the docs.
  2. Add your styles.css file to the pages directory.
  3. 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