Fonts / What the engine does with it
Using a variable font in a paged document, and when not to
One file carrying a continuous range of weights instead of several files carrying fixed ones, which solves a download problem a generated document does not have.
What is actually going on
A variable font exists to avoid shipping five files to a browser when a page uses five weights. A generated document has a different economics: it is rendered once, on a machine, and the download happens on a connection you control, so the saving is small. Against that, a variable font puts a burden on the whole downstream chain. What ends up embedded in the finished file depends on the engine, and tooling further along, a preflight tool, a validator, a printer's workflow, may handle a variable font differently from a static one or not at all. That is a lot of uncertainty to accept in exchange for a download saving on a render nobody is waiting for.
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.
- Prefer static instances for the weights you actually use. Three static files is a smaller set of unknowns than one variable file, and the download difference does not matter here.
- If you use a variable font, use named instances at the axis values you need rather than arbitrary interpolated values, so the result is a weight the designer drew rather than one between two of them.
- Verify what ended up in the output rather than assuming. Open the finished document's font list and see what is actually embedded.
- Check the whole downstream chain before committing, especially if the document goes to a printer or through a conformance check. That is where the handling differences show up.
- Do not animate or vary an axis across the document. A weight that drifts is a weight nobody chose, and in print it reads as an error.
- Where the document has to satisfy an archiving standard, static instances remove a question you would otherwise have to answer.
What it looks like
A fragment, with the wrong version kept in a comment where the wrong version is the thing people actually write.
/* Preferred for a generated document: static instances at the weights
used, which is a smaller set of unknowns than one variable file. */
@font-face {
font-family: "Brand Sans";
src: url("brand-sans-400.woff2") format("woff2");
font-weight: 400;
}
@font-face {
font-family: "Brand Sans";
src: url("brand-sans-700.woff2") format("woff2");
font-weight: 700;
}
/* If a variable font is used, declare the supported range honestly and
use values within it that correspond to instances the designer drew. */
@font-face {
font-family: "Brand Variable";
src: url("brand-variable.woff2") format("woff2-variations");
font-weight: 300 800;
}
h1 { font-family: "Brand Variable"; font-weight: 700; } /* a named instance */
/* not: font-weight: 642; */What people do instead
Adopting a variable font in a document pipeline for the file-size benefit. The benefit is a download saving on a render nobody is waiting for, and the cost is uncertainty about what is embedded and how every downstream tool treats it. That is the wrong trade for a document, and the right one for a website.
How to find out rather than assume
Render the document and inspect the fonts embedded in the output. Confirm you got what you expected and that the weights used are the weights you asked for. If the document goes to a printer or through a validator, put a real file through that path before adopting the font, not after.
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.
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.
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.
Small caps, oldstyle figures and other OpenType features in a PDF
Optional glyph substitutions built into a font, which are the difference between real small capitals and shrunken capitals, and which are off unless asked for.
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.
Why an archival PDF has to embed every font it uses
Every conformance standard requires the actual font program to be inside the file, because a font named but not embedded is a promise that some other machine will have it, and archiving exists precisely because that promise fails.
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.