Fonts / What the engine does with it
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.
What is actually going on
Font size is not the height of anything. It is a nominal value, and the actual height of a line comes from metrics stored in the font: how far the design rises above the baseline, how far it drops below, and how much gap the designer wanted between lines. Those values differ between families, and they differ by more than people expect. So the same stylesheet, at the same font-size and the same unitless line-height, produces visibly different line spacing with two different fonts, and a layout tuned to fit exactly twenty-eight lines on a page fits twenty-six when the font changes. This is also why a fallback with different metrics reflows a document: it is not just the character widths, it is the line box too.
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.
- Set line-height as a unitless multiplier so it scales with the font size, and then check what it produced rather than trusting the number.
- Measure lines per page rather than reasoning about leading. That is the number the layout depends on and it is the number that changes.
- When changing font, re-check every place where content was tuned to fit: tables sized to a row count, blocks meant to stay whole, anything with a fixed height.
- Choose a fallback with similar metrics if pagination matters, which on a document it always does.
- Do not fix a spacing difference by changing font-size. That changes the type size to compensate for a leading difference and makes the document quietly inconsistent with its own scale.
- Remember a taller line box also changes where the first baseline sits, so a block can look vertically offset even when its spacing is correct.
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 {
--text: 9.5pt;
--leading: 1.45; /* unitless, so it scales with the size */
}
body {
font-size: var(--text);
line-height: var(--leading);
}
/* Do not compensate for a font's metrics by changing the type size. If a
family runs tall, adjust the multiplier, not the size, so the document
keeps one type scale.
body { font-size: 9pt; } <-- not this, to fix spacing */
/* Where a fixed number of lines has to fit, state the assumption in the
markup so the next person knows it is load-bearing. */
.ledger tbody tr {
/* 16pt rows: 42 fit the text block at the current metrics.
Re-measure if the family changes. */
height: 16pt;
}What people do instead
Treating font-size as a height and assuming two fonts at 10 point occupy the same vertical space. They do not, the difference compounds down a page, and it surfaces as a table that used to fit and now runs onto a second page after a font change nobody connected to it.
How to find out rather than assume
Render a full page of body text in the old font and the new one and count the lines. If the counts differ, every fixed-height and fit-to-page assumption in the document needs rechecking. Counting takes a minute and is the only reliable version of this check.
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.
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.
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.
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.
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.
line-height 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.