Custom fonts make your site stand out, but poorly optimized fonts hurt your Core Web Vitals.

For best performance, self-host custom fonts on your Remix Server.

Third-Party Fonts

Preconnect to third-party domain to improve fetch time when using services like Google Fonts.

// app/root.tsx
export const links: LinksFunction = () => {
return [
{ rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous"},
]
}

The crossOrigin attribute is necessary when loading third-party fonts. See Michael Crenshaw article for details.

Self-Hosting Fonts

Every byte counts, use a web font tool like Font Squirrel to minimize font size:

Font Squirrel Logo

For a deep-dive on creating web fonts, see Creating Font Subsets by Markos Konstantopoulos:

Font Size Comparison

Before and After

Unblock Render with Font Swap

WebPageTest Performance Report

When fonts are loaded with default display settings, like font-display="block", browsers will hide text entirely for several seconds instead of showing text with a fallback font.

To avoid this behavior, always add font-display: swap to fallback to system fonts:

// styles/fonts.css
@font-face {
font-family: "Qualy";
src: url("/fonts/Qualy.otf");
font-style: normal;
font-display: swap;
}

Eliminating CLS from Fonts

You may notice a Cumulative Layout Shift (CLS) penalty after adding font-display: swap.

This happens because some elements may resize as custom fonts streamed in, and can be avoided by providing metric overrides for the fallback fonts:

// styles/fonts.css
@font-face {
font-family: "Qualy Override";
font-style: normal;
font-weight: 400;
src: local("Helvetica Neue"), local("BlinkMacSystemFont"), local("Arial"), local("Noto Sans"), local("Segoe UI"), local("Roboto"), local(-apple-system), local(sans-serif), local(ui-sans-serif);
ascent-override: 84.57%;
descent-override: 27.27%;
line-gap-override: 0.00%;
size-adjust: 115.30%;
}

Add the override to the font family. The syntax for this step may differ depending on your styling framework.

On Nalu, we add them to our TailwindCSS theme:

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
extend: {
fontFamily: {
logo: ["Qualy", "Qualy Override"],
body: ["NunitoSans", "NunitoSans Override"],
}, 
  },
};

Calculating Font Metric Override

Calculating font metric override is a bit of an involved process, check out Simon Hearne article for the nitty-gritty details:

How to avoid layout shifts caused by web fonts

Luckily, we can skip all the math with a simple command, thanks to the Pixel Point team!

npx fontpie ./qualy-regular.woff2

Further Reading

Improving Web Vitals in Remix
By xhomu
Improving Web Vitals in Remix
Fixing Dependency Errors in Remix
By xhomu
Fixing Dependency Errors in Remix

The next series of Remix articles will cover our favorite Remix UI Patterns used on Nalu!

Nalu is a wiki engine built on Remix and MDX.

NaluNalu