Fonts / Getting the font into the document
Designing a font fallback chain for a document you cannot see
The list of families after the one you want, which decides what the document looks like on the day the font does not load.
What is actually going on
A fallback chain is a contingency plan that runs unattended. The font is fetched over a network at render time, and on the day that fetch is slow or fails, the chain decides whether the document is slightly different or completely broken. The difference between those two outcomes is almost entirely about metrics: a fallback whose characters are close in width to the primary produces a document with the same pagination and slightly different letterforms, and a fallback that is wider reflows every line, which pushes content onto pages it was never meant to be on, which breaks the table that was tuned to fit and the block that was meant to stay together.
How fonts reach this API
There is no font option on the render. A font arrives the way every other subresource arrives: your @font-face names a URL, the renderer fetches it while the document loads, and what was used is embedded in the output. So there is no font upload, no list of available fonts, no substitution control and no subsetting switch. It also means the two failures that actually stop a font are network-shaped rather than typographic: the URL has to be absolute and publicly reachable, and the fetch has to finish before the page is captured. Everything else on this page is decided in your stylesheet and in the font file itself.
The decisions
Reasons rather than a description of the code. Each of these has a default, and the default is chosen by the engine rather than by you.
- Put a metrically similar family second, not a generic keyword. The point of the second entry is that the document still fits when it is used, and a family with different metrics reflows everything.
- End the chain with a generic keyword anyway, so there is always a terminal case, but do not let the generic be the only fallback.
- Choose the fallback for the writing systems the document actually contains. A Latin fallback behind text that includes another script produces boxes, and which script it is decides which fallback helps.
- Set font-display so you know whether a slow font produces a wait or a swap, rather than finding out per render.
- Keep the chain identical everywhere in the document. Two elements with different chains will diverge on the day the primary fails, and the document will look broken rather than merely different.
- Test the failure explicitly. The chain is the code path that only runs on the worst day, so it is the code path least likely to have been looked at.
What it looks like
A fragment, with the wrong version kept in a comment where the wrong version is the thing people actually write.
:root {
/*
* First: the font we want.
* Second: a widely available family with similar metrics, so that if the
* first does not load the pagination survives.
* Last: a generic, so there is always a terminal case.
*/
--font-body: "Brand Sans", "Source Sans 3", Arial, sans-serif;
--font-mono: "Brand Mono", "DejaVu Sans Mono", "Courier New", monospace;
}
body { font-family: var(--font-body); }
code, pre, .ref { font-family: var(--font-mono); }
/* One chain, used everywhere. Two different chains diverge only when the
primary fails, which is the moment consistency matters most. */What people do instead
Ending the chain at sans-serif and calling it done. The generic resolves to whatever the rendering environment has, whose metrics you do not control and have never measured, so the failure case is a document of an unknown number of pages. The second entry is the one doing the work and it is the one usually left out.
How to find out rather than assume
Point the @font-face src at a URL that does not resolve and render the document. Count the pages and compare against a good render. If the count changed, the fallback metrics are too far from the primary and a bad network day will produce a document that is wrong rather than merely plainer.
Frequently asked
Can I upload a font instead of serving one?
No. There is no font upload and no font list. The renderer fetches what your @font-face points at, so the file has to be somewhere it can reach over the network. In practice that means a public URL on your own asset host or a font service, and it means a font on a private path or behind an authenticated endpoint fails to load silently and the fallback is used instead.
How do I know which fonts ended up in the document?
Open the finished file in a reader and look at its document properties, which list the embedded fonts. That list is the truth: it says whether the face you meant was used, whether a fallback was substituted, and how many faces the document is carrying. It is a five second check and it catches most of the failures in this cluster.
Why does the font work in my browser and not in the render?
Almost always because the URL resolves for you and not for the renderer. A relative path, a local file, a development host, or an asset behind a login all work while you are looking at the page and none of them work when a machine somewhere else loads it. The fallback is then used and nothing reports an error, which is why the symptom is a document that looks subtly wrong rather than a render that failed.
Related font topics
The topics that cause each other, then the rest of the same group.
Which font file format to serve for a document that embeds it
WOFF2, WOFF, TTF and OTF all work, and the one you serve changes the download size, not what ends up in the finished document.
Faux bold and faux italic, and how to tell you are getting them
What the engine does when you ask for a weight or a style the family does not have: it makes one up, and the result is worse than the real thing in ways that are easy to miss.
Why two fonts at the same size give different line heights
The ascent, descent and line gap recorded inside the font file, which decide how tall a line is before your stylesheet says anything.
Whether your font licence lets you embed it in a generated document
Embedding a font into a document distributes that font, and whether you are permitted to do that is a question about the licence rather than about the technology.
font-display in paged output
The property behind this decision, with its real support status.
Every font topic
The full list, grouped by supply, engine behaviour, and what happens to the text afterwards.
Fonts reach a render the way every other subresource does, over the network from the URL you named. Render the document and look at what actually got embedded.