Optimize Web Performance with Nuxt Fontaine

Optimize Web Performance with Nuxt Fontaine

3 min read

In web performance work, we often obsess over backend optimizations and miss easy, high-impact wins on the frontend. One such win is font rendering. In a previous article I covered using PartyTown to offload third-party scripts; today we’ll focus on fonts—specifically, font metric fallbacks—and how to implement them in Nuxt with Nuxt Fontaine.

What Is Nuxt Fontaine?

Nuxt Fontaine is a Nuxt 3 module that automatically creates local fallback faces with font metric overrides to cut Cumulative Layout Shift (CLS)—using pure CSS, with zero runtime.

The underlying library, fontaine, also works outside Nuxt, giving you broader flexibility.


Key Benefits

On the module’s playground, enabling Fontaine drastically improves CLS (e.g., from 0.34 → 0.013) and boosts performance.


Installation

Use the nuxi one-liner—or choose your package manager:

# Recommended
npx nuxi@latest module add fontaine

Or manually:

# pnpm
pnpm add -D @nuxtjs/fontaine

# yarn
yarn add -D @nuxtjs/fontaine

# npm
npm install -D @nuxtjs/fontaine

Basic Usage (Nuxt 3/4)

Add the module to your nuxt.config.ts:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/fontaine'],
  // Optional: declare fonts not defined via @font-face (e.g., Google Fonts)
  // fontMetrics: {
  //   fonts: ['Inter', { family: 'Some Custom Font', src: '/fonts/custom.woff2' }],
  // },
})

That’s it—Fontaine handles the rest.

Tailwind CSS Integration

If you’re using Tailwind and define a custom font, add the fallback alias:

// tailwind.config.ts
import type { Config } from 'tailwindcss'
import { fontFamily } from 'tailwindcss/defaultTheme'

export default <Partial<Config>>{
  theme: {
    extend: {
      fontFamily: {
        sans: ['Roboto', 'Roboto fallback', ...fontFamily.sans],
      },
    },
  },
}

This ensures Tailwind utilities include the correct fallback.

How Fontaine Works

Fontaine scans your @font-face definitions and generates matching fallback rules with correct metrics. For example:

/* Your definition */
@font-face {
  font-family: 'Roboto';
  font-display: swap;
  src: url('/fonts/Roboto.woff2') format('woff2'),
       url('/fonts/Roboto.woff') format('woff');
  font-weight: 700;
}

/* Generated fallback */
@font-face {
  font-family: 'Roboto fallback';
  src: local('Segoe UI'), local('Roboto'), local('Helvetica Neue'),
       local('Arial'), local('Noto Sans');
  ascent-override: 92.7734375%;
  descent-override: 24.4140625%;
  line-gap-override: 0%;
}

Then Vue or Nuxt automatically updates your font stacks:

:root {
  font-family: 'Roboto'; /* becomes */
  font-family: 'Roboto', 'Roboto fallback';
}

Tip: Inline Critical Styles for Zero CLS

Fontaine eliminates font-related CLS, but stylesheet loading may still cause shifts. To fully avoid this, inline your CSS during SSR:

// nuxt.config.ts (Nuxt 4)
export default defineNuxtConfig({
  modules: ['@nuxtjs/fontaine'],
  inlineStyles: true, // inline styles during SSR for layout stability
})

This aligns with the approach behind the PR aiming to inline all CSS in Nuxt.

Complementary Tool: Nuxt Fonts

To optimize font delivery (subsetting, preloading, hosting), consider using @nuxt/fonts. It includes Fontaine-powered metrics optimization plus font loading strategies.

Summary & Best Practices

Beyond Nuxt

Want metric‑matched fallbacks outside Nuxt? Use the fontaine library in pipelines (e.g. Vite, Webpack) suitable for Astro, Next.js, and beyond.

By combining Nuxt Fontaine, style inlining, and possibly Nuxt Fonts, you’ll achieve smoother, shift-free font loading—and a significantly better user experience.

Posts

back