简体   繁体   中英

React - How to check if a specific font-face has been loaded?

Let's say I have a font face like:

@font-face {
    font-family: 'MyGreatFont';
    src: url(~"./font/greatfont.woff2") format('woff2'),
        url(~"./font/greatfont.woff") format('woff');
    font-weight: 600;
    font-style: normal;
}

In places where I use it, I do something like: font-family: 'MyGreatFamily', san-serif .

To avoid the Flash of Unstyled Text especially on devices that have slower download speeds, I want to style the fallback font differently than I would my web font.

To that end, I have several questions. I've done some reading on document.fonts and its methods, check , ready and onloadingdone .

First, I'm not quite sure what arguments to give document.fonts.check such that it returns true once my page is fully loaded. I have tried check('MyGreatFont') , check('600 MyGreatFont') , check('1em MyGreatFont') , and even tried the computed value of the font size: check('19.2px MyGreatFont) .

All return either false (which is not right because I know my page is fully loaded with the web font being applied) or an error: Uncaught DOMException: Failed to execute 'check' on 'FontFaceSet': Could not resolve 'Niche' as a font.

Second, as I may have multiple web fonts on a page, I want to apply my special styling when a specific web font is available. Is there a way to do that?

So far, I have:

const MyPageComponent = () => {
    const [webFontsLoaded, setWebFontsLoaded] = useState(false)

    useEffect(() => {
        async function areFontsReady() {
            await (document as any).fonts.ready
            setWebFontsLoaded(true)
        }

        areFontsReady()
    })

    return (
        <div className={`${webFontsLoaded ? 'web-fonts-styling' : 'fallback-font-styling'}`}>
            Content here
        </div>
    )
}

But what this does is that it correctly applies the fallback styling when the webfont isn't loaded but continues to apply the fallback styling when the web font is loaded and rendered to the screen. Only after ALL fonts are loaded in does the styling change. This is to be expected because I am using the document.fonts.ready function.

Is there a way to repeatedly call the check function (using the proper arguments?) so that I know when to toggle my styling?

Note: I would prefer to achieve this behavior without the use of third-party libraries (including JQuery, Font Face Observer, etc.)

As others have already mentioned, use-font-face-observer solves this problem. I have solved my problem in a project with React + Vite doing this:

First, install the package

npm install use-font-face-observer

Let's say you have this CSS:

@font-face {
  font-family: 'Roadgeek 2000 Series C';
  /* Rest of the styles... */
}

You have to match that name in your jsx code:

import useFontFaceObserver from 'use-font-face-observer';

export function SomeComponent() {
  const isFontLoaded = useFontFaceObserver([
    { family: 'Roadgeek 2000 Series C' }, // Same name you have in your CSS
  ]);

  useEffect(() => {
    console.log("Is font loaded?", isFontLoaded);
  }, [isFontLoaded]);

  return (
    // Your jsx goes here...
  )
}

In your console you will see something like this

Is font loaded? false
Is font loaded? true

That variable automatically changes when that font is loaded.

I think the best way to observe the @font-face other than CSS is with javascript. checkout this tiny library fontfaceobserver and also this blog for more improve-your-app-first-load-by... .

And also if you are using react make sure to use useLayoutEffect because in other hooks like useEffect the font is already loaded and ready, you should be able to access it before react itself.

use-font-face-observer has a hook for this

const webFontsLoaded = useFontFaceObserver([{family: `MyGreatFont`}]);

https://www.npmjs.com/package/use-font-face-observer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM