Skip to content

πŸ”€ Font metric overrides to reduce CLS

License

Notifications You must be signed in to change notification settings

nuxt-modules/fontaine

Folders and files

NameName
Last commit message
Last commit date
Feb 4, 2025
Mar 19, 2025
Jan 25, 2025
Jan 25, 2025
Sep 2, 2022
Sep 2, 2022
Dec 21, 2023
May 17, 2024
Sep 2, 2022
Sep 2, 2022
Jan 25, 2025
Apr 10, 2024
Apr 10, 2024
Mar 24, 2025
Mar 24, 2025
Sep 2, 2022
Sep 21, 2024
Sep 2, 2022
Dec 4, 2023
Dec 4, 2023

Repository files navigation

Nuxt Fontaine

npm version npm downloads Github Actions Codecov

Font metric fallback implementation for Nuxt 3

Features

⚠️ @nuxtjs/fontaine is under active development. ⚠️

  • πŸ’ͺ Reduces CLS by using local font fallbacks with crafted font metrics.
  • ✨ Generates font metrics and fallbacks automatically.
  • ⚑️ Pure CSS, zero runtime overhead.

On the playground project, enabling/disabling this module makes the following differences rendering /, with no customisation required:

Before After
CLS 0.34 0.013
Performance 88 98

What's next

For best performance, you will need to inline all your CSS, not just the font-face fallback rules (which this module does automatically), or there will still be a layout shift when the stylesheet loads (which is why the number above is not zero).

This PR aims to bring that ability to Nuxt itself.

Installation

npx nuxi@latest module add fontaine

Usage

export default defineNuxtConfig({
  modules: ['@nuxtjs/fontaine'],
  // If you are using a Google font or you don't have a @font-face declaration
  // for a font you're using, you can declare them here.
  //
  // In most cases this is not necessary.
  //
  // fontMetrics: {
  //   fonts: ['Inter', { family: 'Some Custom Font', src: '/path/to/custom/font.woff2' }],
  // },
})

That's it!

Tailwind CSS

If you use Tailwind CSS and use your custom font via the config file, you will need to manually add the fallback font.

import type { Config } from 'tailwindcss'
import { fontFamily } from 'tailwindcss/defaultTheme'

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

How it works

Nuxt will scan your @font-face rules and generate fallback rules with the correct metrics. For example:

@font-face {
  font-family: 'Roboto';
  font-display: swap;
  src: url('/fonts/Roboto.woff2') format('woff2'), url('/fonts/Roboto.woff') format('woff');
  font-weight: 700;
}
/* This will be generated. */
@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, whenever you use font-family: 'Roboto', Nuxt will add the fallback to the font-family:

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

Using outside of Nuxt

The core of this module will work outside of Nuxt, and has been separated into a separate library: fontaine. Check it out!

πŸ’» Development

  • Clone this repository
  • Enable Corepack using corepack enable
  • Install dependencies using pnpm install
  • Stub module with pnpm dev:prepare
  • Run pnpm dev to start playground in development mode

Credits

This would not have been possible without:

License

Made with ❀️

Published under the MIT License.