Skip to content

Using custom fonts with Hyvä

There are several ways to include a custom font in the theme.
Each work, but if done carelessly google ranking metrics can suffer.

The performance impact depends not only on the method of inclusion but also on other variables like server and caching configuration.
In general, the performance differences between the options are very small and sometimes barely noticeable within the normal Pagespeed fluctuations.

Tailwind configuration

Regardless of how you add your font files, the font has to be used in your css files as the font-family like font-family: 'Roboto', sans-serif;.

To use it with tailwind, add the font to your tailwind.config.js file. See the tailwind documentation on several approaches to declare the font, for use as default font-sans example:

theme: {
    extend: {
      fontFamily: {
        sans: ['Roboto', ...defaultTheme.fontFamily.sans]
      }
    }
  }

For this to work, the defaultTheme object needs to be imported.
Add the following to the head of the file to do so:

const defaultTheme = require('tailwindcss/defaultTheme');

Google fonts

When selecting a google font on fonts.google.com, a default implementation is presented:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">

You can include a slightly altered version in your Magento_Theme/layout/default_head_blocks.xml file.
Note that in the URL the ampersand is noted as the HTML &amp; notation.

<link src="https://fonts.googleapis.com/css2?family=Roboto&amp;display=swap" rel="stylesheet" type="text/css" src_type="url"/>

To add the preconnect resources, add a custom block to the head.
For example:

<referenceBlock name="head.additional">
    <block class="Magento\Framework\View\Element\Text" name="custom.fonts">
        <arguments>
            <argument name="text" xsi:type="string">
                <![CDATA[
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
                ]]>
            </argument>
        </arguments>
    </block>
</referenceBlock>

Using Google fonts from Google servers

Be careful when using Google fonts from the Google servers, since that is by default not compliant with the GDPR.
German websites have been fined for using automatically requested Google fonts.
To use the Google font files locally, use this helper to quickly select the desired formats and download the files and code. See further on how to include the local files.

Local font files

You can use custom font files or use downloaded google font files and include them locally from your web server.
You will use some @font-face css rules to register the available fonts and reference the location of the font files.

For Example:

@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/roboto.woff2) format('woff2');
}

Each different font in the family (they differ in font-weight and font-style) has its own declaration.
Note that these declarations don't load the font automatically. The font is loaded only when it's used in the css as a font-family property like font-family: "Roboto"; or the appropriate tailwind class.

While there used to be some different formats in font files (.ttf, .otf, .eot) it is recommended to use only woff2 or woff files nowadays.

Add the font files to a fonts/ folder in your themes web/ folder.
Add the font-face styles to a css file, for example in web/tailwind/components/typography.css.
Make sure the paths to the font files are correct, the generated css file will be in web/css so ../fonts/ will refer to web/fonts/.

Preloading/preconnect

Preloading fonts

It is often recommended to preload fonts that are used above the fold to ensure the fastest possible delivery.
This helps avoid layout shifts, however doing so impacts the LCP, since preloading fonts blocks the first render.

To avoid layout shifts, instead set the right system fallback fonts and line-heights (reserve space).
You can also use size-adjust and ascent-override on the fallback font, and you can calculate these dynamically for some fonts (for example the Google ones).

If you still choose to preload fonts despite the warning, please read on.
You preload local fonts by adding the following snippet to your Magento_Theme/layout/default_head_blocks.xml file in the <head> section:

<font src="fonts/roboto.woff2"/>

This will preload the given URL. When using files with multiple font formats in it, it’s better to use preconnect.
You have to use a custom block for this:

<referenceBlock name="head.additional">
    <block class="Magento\Framework\View\Element\Template" 
           name="custom.fonts"
           template="Magento_Theme::head.phtml" />
</referenceBlock>

Where in head.phtml you can use something like:

<link rel="preconnect" 
      href="<?= $block->getViewFileUrl('fonts/roboto.woff2') ?>">

There are different opinions on whether to use preloading or not. Test your environment to make sure it has the desired outcome.

Font-display options

In most cases, the swap value for the font-display property is the best way to go. Displaying text fast is a priority here, but the webfont will be loaded eventually. This has to happen fast because layout shifting can occur when it takes too long.
When the optional value is used, the webfont won’t be shown at all when it arrives too late.

Depending on your situation, other options might be interesting also.

PostCSS plugin

You can also use the node package postcss-font-magician. By just adding the location of your font files to the PostCSS config, the styles are automatically added to styles.css, for example:

require('postcss-font-magician')({
   hosted: ['../fonts/', '../fonts']
})

Further in-depth information

For more in general best practices, see Best practices for fonts on web.dev.