🚀 Font Fallbacks #
In this Astro font fallbacks post, we see how you can use Capsize to reduce layout shift caused by font swaps. We focus on self-hosted fonts in vanilla CSS here, though you can apply the techniques elsewhere. Before tucking into the detail, we will unpack some terms just mentioned.
Font Swap #
When you use web fonts or Google fonts on a site, it can take a moment for them to be downloaded
to the user device, especially if they have a slow internet connection. By default, the user
will see nothing, where the text should be, while the font gets downloaded in the background. To
improve user experience, you will typically want to add the font-display: swap
directive to your @fontface
CSS. This tells the browser to display
the text using a fallback font initially. That improves user experience as the visitor can start
reading while the web font downloads. The browser swaps out the fallback for the web font, once it
has downloaded it, so the page will ultimately look as the designer wanted it to.
Font Swap Layout Shift #
We solve one user experience issue, but potentially introduce another. That is because not all fonts are the same size! When the browser switches from fallback to web font, there is typically some layout shift, just resulting from the two fonts having different metrics. This becomes more pronounced on narrower displays. Cumulative Layout Shift (CLS) is not great; it can be annoying if a button that you want to tap shifts just before your finger hits the screen.
One trick to reduce this font swap layout shift is to use modern CSS to adjust the metrics of the fallback font. Doing this, the fallback font will not look exactly as it should, but the shift can be dramatically reduced, or even eliminated on font swap. We look at techniques for doing that here, using Capsize.
😕 What is Capsize? #
Capsize is a typography tool for text layouts . Creating precise text layouts can be frustrating, just from the way font sizing is defined. Capsize helps here, making your text height and the spacing above and below more predictable. The font metric data it uses here are also handy for working out the modern CSS adjustments we can make to a fallback font, so its layout approximates the web font’s.
An alternative to Capsize for reducing font swap layout shift is Fontaine . It has a Vite plugin, and is able automatically to update font face CSS (like we will do, using Capsize metrics). We do something a little more manual here with Capsize, just to help get a grounding in the issue and solution approach.
🧱 What are we Building? #
We won’t build a site from start-to-finish. Instead, we will jump into snippets for a basic example with vanilla CSS and self-hosted fonts. There is a link to the complete code further down the page. You will be able to use that code to play around a little with font swaps and see the impact of our approach.
If you are new to working with self-hosted fonts in Astro, see the Astro Self-Hosted Fonts workflow video to get up to speed. If you want more background on font swapping and fallbacks, before continuing, see the thorough article by Katie Hempenius on Chrome Developers .
🌍 Astro Font Fallbacks: Global Styles #
Our first code snippet is the global style sheet. The most important feature here is setting and using a custom CSS property for the font family:
We will override that property in the font fallback CSS which we generate.
💄 font‑face CSS #
These are the font-face directives needed for our Open Sans font. Later, these CSS files will be imported into the Astro markup file.
You can download woff files (and matching font-face directives) for most Google fonts with the google-webfonts-helper app . Note, font-face includes font-display: swap
, which is
important here.
📜 Capsize Script #
Next, I added a TypeScript stand-alone script: capsize-font-fallbacks.ts
in the project root directory. This uses node APIs to output an extra CSS stylesheet; convenient
when working in vanilla CSS. You could, alternatively, use similar code as a utility function to export
styles for use on a DOM element: more useful when working with a CSS-in-JS framework or something like
vanilla-extract.
Capsize Tooling #
You need to add two Capsize packages to your project:
The first package provides createFontStack
, which we use to create
a fallback font CSS directive and some font-face CSS:
You can add {fontFaceFormat: 'styleObject'}
as a second (options)
parameter on createFontStack
here, for output better suited to CSS-in-JS
styling frameworks.
Choosing Fallback Fonts #
Typically, you will want to use Arial as a fallback font for sans-serif fonts, and Times New Roman for serif. The Katie Hempenius article (mentioned above) notes, although these are quite safe fallbacks for desktop devices, neither is available on Android, so Roboto is a good second fallback.
You can import individual fonts from @capsizecss/metrics
, as in
lines 2
– 4
.
Then, combine them into a font stack array. The code adds sans-serif
as a third fallback in the output CSS.
vite‑node
#
You can run TypeScript node scripts in your Astro project by installing vite-node
as a dev dependency. To run vite-node
(after install the package
as a dependency), use:
💅 Generated CSS #
Running the script should create a src/styles/font-fallbacks.css
file:
For the first time, you get to see these mysterious CSS font adjustments (ascent-override
, descent-override
and size-adjust
)!
🏡 Homepage #
The final missing part is the client code for the home page, which will include all the stylesheets we mentioned. An alternative is to place those imports in a layout file, accessible to all site pages.
🗳 Poll #
💯 Astro Font Fallbacks: Frontend #
When you have everything working, try commenting out the fallback CSS import line in your Astro page file to see the difference. You will probably need to throttle the network speed to see the load in detail.
I used Times New Roman as a fallback for a sans-serif font here, just to exaggerate the layout shift. Generally, you will use opt for Arial as a safe sans-serif fallback.
🙌🏽 Astro Font Fallbacks: Wrapping Up #
In this post, we saw a way to implement Astro font fallbacks. In particular, we saw:
-
why using a
font-display: swap
improves user experience; - why you might use Capsize or Fontaine to reduce CLS; and
- how you can use Capsize to generate fallback CSS.
You can see the full code for this project in the Rodney Lab GitHub repo . I do hope you have found this post useful! Let me know if you decide to use Capsize in a production project, or if you preferred Fontaine. Also, let me know about any possible improvements to the content above.
🏁 Astro Font Fallbacks: Summary #
How can you reduce font swap layout shift in Astro? #
- Often, setting the CSS font-display directive to `swap` can improve user experience by making text legible before the page web fonts are all fully loaded. It can add a layout shift as the fallback font gets replaced by the web font, though. Fontaine is a package with a Vite plugin for automatically reducing the shift. It does this by adjusting ascent-override, descent-override and size-adjust modern CSS properties for the fallback fonts. Doing so helps make the fallback font layout more closely resemble the final web font’s layout, reducing layout shift. An alternative to Fontaine is Capsize, which will work with CSS-in-JS tooling, vanilla-extract, or even something more manual. We saw you can try Capsize to help understand the issue and a solution.
How does `font-display: swap` improve user experience? #
- Web fonts can take more than a moment to download, especially on a slow connection. You might see Lighthouse suggest setting the `font-display: swap` directive with a fallback. The idea here, is to pick a fallback font which will already be available on the user’s device, such as Arial, Times New Roman or Roboto. Then, setting `swap` instructs the device to display content using that fallback (instead of a blank patch) while waiting for the web font to download. When the web font finally downloads completely, the device swaps the fallback font for the downloaded web font. This improves user experience, though you will likely have to tweak your implementation to avoid layout shift on font swap.
How does `font-display: swap` introduce layout shift? #
- `font-display: swap` instructs the browser initially to show text in the fallback font, and to swap to the page web font once it is fully downloaded. No two fonts are identical, and the swap will typically result in some layout shift. Modern CSS steps in to help here! Adjusting the metrics of the fallback font, we can make its layout closely resemble the ultimate layout. The CSS `ascent-override`, `descent-override` and `size-adjust` properties are helpful here. However, there is no need to work out the right values to use manually. We have seen that tooling like Fontaine and Capsize can have your back here!
🙏🏽 Astro Font Fallbacks: Feedback #
Have you found the post useful? Would you prefer to see posts on another topic instead? Get in touch with ideas for new posts. Also, if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please consider supporting me through Buy me a Coffee.
Just dropped a new post where we see how you can set it up Capsize in Astro to reduce font swap CLS and play around to see impact the Capsize fallbacks make.
— Rodney (@askRodney) May 17, 2023
Hope you find it useful!
#askRodneyhttps://t.co/meAF4GpeZq
Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter, @rodney@toot.community on Mastodon and also the #rodney Element Matrix room. Also, see further ways to get in touch with Rodney Lab. I post regularly on Astro as well as SEO. Also, subscribe to the newsletter to keep up-to-date with our latest projects.