Web Fonts Without Layout Shifts
Fonts & Loading
`@font-face` loads custom fonts. Self-host for speed; use `font-display: swap` to avoid invisible text.
What you'll learn
- Load a font with `@font-face`
- Pick `font-display` wisely
- Preload critical fonts
To use a font that isn’t on the user’s system, load it with
@font-face.
The Pattern
@font-face {
font-family: "Inter";
src: url("/fonts/inter-var.woff2") format("woff2-variations");
font-weight: 100 900; /* a variable font covers the whole range */
font-style: normal;
font-display: swap;
}
body {
font-family: "Inter", system-ui, sans-serif;
} Reference the family by the name you gave it in font-family.
font-display — Critical For UX
| Value | Behavior |
|---|---|
auto | Browser default — usually like block |
block | Invisible text for up to 3s while loading (FOIT) |
swap | Show fallback immediately, swap to web font when ready (FOUT) |
fallback | Brief block, then swap, then never swap |
optional | Brief block; if not ready, use fallback forever |
swap is the safe default for most pages — users see content
immediately, with a brief font switch when the web font arrives.
Variable Fonts
A variable font is one file with every weight (and sometimes style, slant, optical size). Big perf win over loading separate files per weight.
@font-face {
font-family: "Inter";
src: url("/inter.var.woff2") format("woff2-variations");
font-weight: 100 900; /* declared range */
font-display: swap;
} Preload The Important Font
<link
rel="preload"
href="/fonts/inter-var.woff2"
as="font"
type="font/woff2"
crossorigin
/> Tells the browser to fetch the font immediately, in parallel with HTML parsing. Use only for the first paint’s font — preloading everything is counterproductive.
Self-Host vs Google Fonts
Self-hosting is usually faster:
- No DNS / TLS handshake to Google
- You control caching
- No third-party privacy implications
fonts.bunny.net and Google’s font CDN are fine, but downloading
the WOFF2 once and serving it yourself is straightforward and
better.
Fallback Sizing
The fallback font might be a different size, causing a layout
jump when the web font swaps in. Modern CSS has size adjustment
properties on @font-face:
@font-face {
font-family: "Inter Fallback";
src: local("Arial");
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
} Tools like fontpie generate these numbers automatically.
Up Next
Beyond font-size — letter-spacing, decoration, transformation.
Text Effects →