How to load (and preload) fonts

I havenā€™t explored this further yet. The temporary solution I have is to render a <Global /> component with the @font-face definitions, but the problem here is that the fonts will be required twice on load, because of the hydration of React, causing some flickering.

Imports:

import { css, Global } from "frontity";
import LibreBaskerville from "../../fonts/LibreBaskerville-Regular.ttf";

Font face definition:

<Global
      styles={css` 
        @font-face {
          font-family: "Libre Baskerville";
          font-style: normal;
          font-weight: normal;
          font-display: fallback;
          src: url("${LibreBaskerville}") format("truetype");
        }
    `}
/>

The ideal solution I think is to load the fonts outside of the React cycle somehow. Not sure how to do this and I couldnā€™t find a quick solution around, need to explore it more.

It is important that you define the @font-face in a separeted <Global /> element because if you do this in an existing <Global /> element that might be using a state variable and is subject to rerender, the @font-face definition would be rerendered as well, asking again for the fonts and causing the flickering.

1 Like

I tried this but I get the following error:

ERROR in ./packages/competicion-theme/src/assets/fonts/Metropolis-Bold.ttf 1:0
    Module parse failed: Unexpected character '' (1:0)
    You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
    (Source code omitted for this binary file)

Are you running the last version of frontity? The webpack's font loaders were added after the 1.0 so maybe you are missing that update? I didnā€™t run into that problem.

@orballo did you find out how people using Emotion outside of Frontity is dealing with the hydration process?

A solution for Frontity could be something like this:

{state.frontity.platform === "server" && <Global
      styles={css` 
        @font-face {
          font-family: "Libre Baskerville";
          font-style: normal;
          font-weight: normal;
          font-display: fallback;
          src: url("${LibreBaskerville}") format("truetype");
        }
    `}
   supressHydrationWarning
/>
}

I also wonder if this problem exists when using Emotionā€™s extractCritical, which manually moves all the CSS to the <head> on SSR. We used to do that, but I removed it to be able to have source-maps. Maybe we can add it back in production.

1 Like

Yes, thanks the problem was that! Now I have the fonts loaded!

2 Likes

Iā€™ve done a quick test with TwentyTwenty and I cannot reproduce that problem. Fonts are only requested once for me.

This is the test:

const FontFace = ({ state }) => {
  // I added a dependency on state.router.link so this component is
  // rerendered each time it changes.
  state.router.link;
  // Now I do a console.log to check that component is being rendered
  // successfully on each state.router.link change.
  React.useEffect(() => {
    console.log("The FontFace component has been rendered");
  });

  return (
    <Global
      styles={css`
        @font-face {
          // ... 
        }
      `}
    />
  );
};

Am I doing something wrong? If you want to modify the test, this is the branch: https://github.com/frontity/frontity/tree/fontface-double-request-testing

I tried adding state.frontity.platform === "server" as I commented here but it was not needed, it worked fine without it.

@orballo once you confirm this please let me know!

1 Like

I just checked this and realized that the problem exists in Firefox (and only if the cache is disabled), but not in Chrome. Soā€¦ my bad! Thanks for looking into it though!

Youā€™re right, it happens on Firefox: https://twentytwenty-theme-bbf22ygph.now.sh/

Thanks Eduardo. Iā€™ll check if the state.frontity. platform === "server" trick works in Firefox.

No, it doesnā€™t, but that only happens if the Firefox DevTools are open and ā€œdisable cacheā€ is selected, so I guess itā€™s not something we should worry about. Iā€™m going to leave it as it is.

I agree.

What if I wanted to use fonts form GoogleFonts or Adobe typekit? how can I import these fonts on my Frontity theme?

Looking for best practice for Google Fonts as well. I think itā€™d be something like:

import { Head } from 'frontity'
...
return (
  <Head>
    <link rel="stylesheet" href="//fonts.googleapis.com..."/>
  </Head>
)

Hi, I have the same error. I have the following code:

import GothamBold from "../assets/fonts/Gotham-Bold.otf";
import GothamLight from "../assets/fonts/Gotham-Light.otf";

{state.frontity.platform === "server" && <Global
      styles={css` 
        @font-face {
          font-family: "Gotham Bold";
          font-style: normal;
          font-weight: normal;
          font-display: fallback;
          src: url("${GothamBold}") format("opentype");
        }
        @font-face {
          font-family: "Gotham Light";
          font-style: normal;
          font-weight: normal;
          font-display: fallback;
          src: url("${GothamLight}") format("opentype");
        }
    `}
   supressHydrationWarning
/>
}

The response I get:

ModuleParseError: Module parse failed: Unexpected character '' (1:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

In my package.json it says that the version is ā€œ1.0.0ā€ and that I have the following dependencies:

"@awsmin/f1": "./packages/f1",
"@awsmin/frontity-wp-job-openings": "^1.1.0",
"@frontity/core": "^1.7.3",
"@frontity/html2react": "^1.3.5",
"@frontity/tiny-router": "^1.2.1",
"@frontity/wp-source": "^1.8.2",
"frontity": "^1.11.1",
"frontity-contact-form-7": "^0.1.7"

As a template, I am using @awsmin/f1 (https://awsm.in/awsm-f1/) theme. What exactly should I do?

Hi @tix,

With the current version of Frontity you cannot load otf files directly from JS.

Have a look at this thread to understand why

Thanks for the reply. I thought Iā€™ve gone mad or something to not figure this out. :slight_smile:

1 Like

Hi
I guess when working with Google Fonts you can just drop the &display=swap that comes on the end of the served URL. The font will behavior as a font-display: block;

ex. <link href="https://fonts.googleapis.com/css2?family=Bebas+Neue" rel="stylesheet" />

For me, it worked pretty fine, without real notice of the delay, and giving - in my opinion - an experience way better than with FOUT.

More info on font-display property

2 Likes

I felt this post needed a clarification. Although, as of January, you cannot load otf files, loading other font files (ttf, woff, woff2, eot) is possible using the pattern on the following thread:

This seems to be an efficient way to load Google fonts as of now. Hopefully this will save someone the couple of hours worth of confusion I had when thinking a direct file import would not work.

2 Likes

Quick note . I found this simple method for resolving FOUT (Flash of Unstyled Text) in React

useEffect(() => {
  document.fonts.load("12px Merriweather").then(() => setIsReady(true));
}, [])

And then check isReady before showing your page content

1 Like

First, make sure you have the font files (usually in formats like .woff, .woff2, .ttf, or .otf) that you want to use on your website Century Gothic Font Family. You may obtain these files from the fontā€™s official website or other reliable sources.