This plugin makes it easy to implement FOFT (flash of faux text) as a font loading strategy, as opposed to the less desirable FOUT (flash of unstyled text) and FOIT (flash of invisible text). With FOFT, you can load critical fonts faster and minimize the amount of reflow for bold/italic font variations, by letting the browser synthesize faux variants and switching to real bold/italic fonts after they are asynchronously downloaded.
For example, if you're using the Lato
font family, you can defer loading of Lato-Bold
since the browser can synthesize faux styles for bold and italics for any font by using a generic algorithm. However, the faux font synthesis algorithm isn't perfect. Font design is an art, which means that there are artistic and ergonomic differences between a synthesized bold style and a hand-crafted font such as Lato-Bold
. Ideally we want to use Lato-Bold
instead of a synthesized bold, but it's acceptable to temporarily show a synthesized bold while waiting for the true Lato-Bold
font to be downloaded and switching over when the download is done. The (less desirable) alternative would be to either block DOMContentLoaded
while all Lato
variations are downloaded, or asynchronously downloading the entire font family, causing a long period of FOUT/FOIT.
You can tune the balance between performance and user experience with simple configurations. This plugin generates inline @font-face CSS declarations and preloads fallback fonts based on a preloadDepth
configuration vlue, which lets you specify how many fonts to preload and how many to load asynchronously.
This package provides:
- A fusion plugin that generates @font-faces and preloads fallback fonts based on app-level font configuration.
- A Higher Order Component for loading custom web fonts (and associated utils). During font loading, this HOC temporarily swaps the element to a well-matched fallback font, avoiding FOIT and FOUT. See https://www.zachleat.com/web/comprehensive-webfonts/#critical-foft-preload for more on this.
yarn add fusion-plugin-font-loader-react
Consuming apps should define a font-config.js
which a) provides data for @font-face generation, b) is used to derive the fallback font and styles that will be used by the with-font-loading.js
HOC.
// src/font-config.js
import {assetUrl} from 'fusion-core';
export const preloadDepth = 1;
export const fonts = {
'Lato-Regular': {
urls: {
woff: assetUrl('../static/Lato-Regular.woff'),
woff2: assetUrl('../static/Lato-Regular.woff2'),
},
fallback: {
name: 'Helvetica',
},
},
'Lato-Bold': {
urls: {
woff: assetUrl('../static/Lato-Bold.woff')
woff2: assetUrl('../static/Lato-Bold.woff2'),
},
fallback: {
name: 'Lato-Regular',
styles: {
'font-weight': 'bold',
},
},
},
'Lato-Thin': {
urls: {
woff: assetUrl('../static/Lato-Thin.woff'),
woff2: assetUrl('./static/Lato-Thin.woff2'),
},
fallback: {
name: 'Lato-Regular',
styles: {
'font-weight': '100',
},
},
},
};
Based on the example configuration file above the following @font-face would typically be generated in
@font-face {
font-family: 'Lato-Regular';
src: url('/_static/ca614426b50ca7d007056aa00954764b.woff2') format('woff2');
}
@font-face {
font-family: 'Lato-Bold';
src: url('/_static/ca104da8af9a2e0771e8fe2b31f8ec1e.woff2') format('woff2');
}
@font-face {
font-family: 'Lato-Thin';
src: url('/_static/03b64805a8cd2d53fadc5814445c2fb5.woff2') format('woff2');
}
- An in-memory font fallback tree is generated at runtime based on the defintitions provided in
font-config.js
- Fallbacks at and above the specified
preloadDepth
will be preloaded/prefetched on page load - Remaining fonts will lazily loaded.
Based on the sample config above (preloadDepth
is set to 1), the HOC example above would yield the following values for prop.$fontStyles
:
while loading font:
{
fontFamily: 'Lato-Regular',
fontWeight: 'bold',
}
when font is loaded:
{
fontFamily: 'Lato-Bold',
}
preloadDepth = 0
: Every font is preloaded, there are no fallback fonts. There is no FOFT or FOUT but there may be some FOIT
Use this when jank-free font loading is more important than page load performance.
preloadDepth = 1
: Preload roman (non-stylized, e.g. Lato
) fonts. Stylized fonts (e.g. Lato-Bold
) will be lazily loaded and will fallback to preloaded font. During fallback period the browser will apply the appropriate style to the roman font which will display a good approximation of the stylized font (FOFT) which is less jarring than falling back to a system font.
Use this when you want to balance performance with font-loading smoothness
preloadDepth = 2
: Don't preload any fonts. Lazily load all fonts. Lazily loading fonts will immediately fallback to the system font (FOUT).
Use this when page load performance is more important than font-load smoothness
// src/main.js
import App from 'fusion-core';
import FontLoaderReactPlugin, {
FontLoaderReactConfigToken,
} from 'fusion-plugin-font-loader-react';
export default () => {
const app = new App(<div />);
// ...
app.register(FontLoaderReactConfigToken, {
fonts,
preloadDepth,
});
app.register(FontLoaderReact);
// ...
return app;
};
// src/some-component.js
import {withFontLoading} from 'fusion-plugin-font-loader-react';
const FancyLink1 = withFontLoading('Lato-Bold')(
styled('a', props => ({
':hover': {fontSize: `${props.answer}px`},
...props.$fontStyles,
}))
);
import FontLoaderReact from 'fusion-plugin-font-loader-react';
The Font Loader plugin for React. Adds font loading in the plugin middleware.
import {FontLoaderReactConfigToken} from 'fusion-plugin-font-loader-react';
Defines the font loader configuration.
type FontLoaderReactConfigToken = {
fonts: {
[string]: FontType,
},
preloadDepth: number,
};
import {withFontLoading} from 'fusion-plugin-font-loader-react';
This repo also supplies a with-font-loading.js
Higher Order Component which is used to:
- Load a specified font
- Temporarily assign a fallback font and styles to the wrapped component via
props.$fontStyles
- When the font is loaded assign the true font to child component via
props.$fontStyles
const hoc = withFontLoading('Lato-Bold');
const FancyLink1 = hoc(
styled('a', props => ({
':hover': {fontSize: `${props.answer}px`},
...props.$fontStyles,
}))
);
This will lazy-load Lato-Bold
and meanwhile assign a fallback font and styling to the element via props.$fontStyles
.
const hoc: HOC = withFontLoading((font: string));
font: string
- The name of the font whose loading should be managed by the plugin- returns
hoc: Component => Component
Promise used by with-font-loading.js
HOC to dynamically load specified font; calls resolve
when load is complete.
Uses document.fonts.load
where available (chrome and firefox as of 10/17), otherwise uses a polyfill.