Basic

Fonts and the text that shifts

A web font arrives after the HTML, so the browser paints with a fallback and repaints when the font loads. That repaint is a layout shift and, on a slow connection, a flash of the wrong face. The fix is to make the fallback close and to load the font late but early enough.

What you will see

A face whose fallback box is within two percent of the real one.

About 1 min of reading

Try It

Make one font load without a shift

1

Find the font files

ls -la public/fonts/ | head -10

Before you run it, say out loud what it will print. Then open the answer.

What it prints
The files and their sizes. Any weight that no page uses is a candidate for removal.
2

Declare the fallback

grep -n 'font-family' public/css/main.css | head -5

Before you run it, say out loud what it will print. Then open the answer.

What it prints
The stack. The second name must be a system face with a similar x-height.
3

Add the display rule

grep -c 'font-display' public/css/main.css

Before you run it, say out loud what it will print. Then open the answer.

What it prints
At least one per @font-face. Without it, the default can hide text for a long window.
4

Adjust the metrics

printf '@font-face { font-family: body; src: url(/public/fonts/body.woff2?v=20261010); font-display: swap; size-adjust: 98%%; }\n' | tee -a public/css/main.css

Before you run it, say out loud what it will print. Then open the answer.

What it prints
A face whose fallback box is within two percent of the real one.
Do not preload every font weight. Preload only the file the first paragraph needs, or you pay requests the page never uses.

Data Flow

Font request to stable text
1 HTML parses and text paints in the fallback
↓
2 Font file is requested and arrives
↓
3 Browser swaps the face
↓
4 size-adjust keeps the box nearly identical
Why this works
The subset question

A full Latin font is often larger than the page needs. Subsetting to the characters the page uses is a build step that cuts bytes without changing what renders.

When you have a choice

When to use system fonts

If the design does not depend on the face, a system stack costs zero requests and zero shifts. That is the cheapest accessible win and it is a real design choice.

Examples

Match the fallback metrics

Pick a system fallback with a similar x-height and set size-adjust so the two faces occupy nearly the same box. The repaint then moves almost nothing.

font-display swap or none

swap shows the fallback then swaps, which is usually right. none hides the text for a short window, which is right only for a font that is already cached.

Preload only what is used

Preloading a weight the page never uses costs a request and blocks nothing but still competes for the connection. Preload the one file the first paragraph needs.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Images: size, format, and dimensions
Previous Lesson
Images: size, format, and dimensions
Next Lesson
Scripts: defer, async, or move
Scripts: defer, async, or move →