I am always amazed by what you can do to improve the performance of your website by focusing on the things that initially does not look that complex. In the past, I thought that you can only make your app faster by optimizing backend like database operations, requests, etc. Don't get me wrong, you should still work on your backend code to make the requests faster, but there are several things in the frontend that you can do to make the experience much better.
Some time ago, I wrote an article about Improving Performance of Nuxt with PartyTown that allows you to run third party scripts like Google Analytics as a web worker. You can check it out in the following series.
Today however, I will focus on the fonts and in more details, font face override concept.
What is Fontaine?
Fontaine is a font metric override tool that can:
- Reduce CLS by using local font fallbacks with crafted font metrics.
- Generate font metrics and overrides automatically.
- Pure CSS, zero runtime overhead.
It basically means, that whenever you are using font-face in your project, adding this module to your project will increase the Content Layout Shift (CLS) value of your Lighthouse score, and that will in general improve the performance of your website.
Below, you can see the result of adding the module to the example app using font-face
:
Before | After | |
---|---|---|
CLS | 0.34 |
0.013 |
Performance | 88 |
98 |
To achieve even better performance, you should inline all your CSS, not just the font-face override 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 will be adressed in one of the upcoming releases of Nuxt.
Usage
Usage of this module is really simple and usually does not require any configuration what so ever. First, let's install the module:
pnpm add -D @nuxtjs/fontaine
npm install -D @nuxtjs/fontaine
yarn add -D @nuxtjs/fontaine
Then, add it to your modules
array in nuxt.config.ts
:
export default defineNuxtConfig({
modules: ['@nuxtjs/fontaine']
})
Optionally, you can also add some configuration options if you like:
export default defineNuxtConfig({
modules: ['@nuxtjs/fontaine'],
fontMetrics: {
fonts: ['Inter', { family: 'Some Custom Font', src: '/path/to/custom/font.woff2' }],
},
})
And that's it! By following these simple steps, you can improve the CLS (and overall performance) of your website.
Bonus
I usually like to know how the tool works so that I can understand better whether I need it or not. Let's dive deeper into the code to understand what is going on under the hood.
Let's say, that we want to use the following "Roboto" font-face
declaration in our app:
@font-face {
font-family: 'Roboto';
font-display: swap;
src: url('/fonts/Roboto.woff2') format('woff2'), url('/fonts/Roboto.woff') format('woff');
font-weight: 700;
}
The fontaine
module will generate for us the following code:
@font-face {
font-family: 'Roboto override';
src: local('BlinkMacSystemFont'), 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%;
}
So basically, the module will scan your @font-face rules and generate fallback rules with the correct metrics.
Then, whenever you use font-family: 'Roboto', the module will add the override to the font-family, so instead:
:root {
font-family: 'Roboto';
}
We will get the following code in the final bundle:
:root {
font-family: 'Roboto', 'Roboto override';
}
Summary
Well done! You have just managed to improve the overall performance of your website by using Fontaine and font-face override. Keep in mind however, that this is only the tip of the Iceberg in terms of improving performance so make sure to check out other articles and materials to make your app rapidly fast!
Top comments (2)
Let's say, I have font files in public/fonts/x/(x-regular.otf, x-thin.otf, other weights) then Do I have to write font face rules to css file?(don't have anything right now, how do I generate this automatically - which most of the project required)
and nuxt config
and using unocss with this config
but this seems not working
Hey,
Not sure what the problem can be. Can you report an issue in the github repository of the module?