A print designer specifies type once. The page is a fixed size, the stock is known, the reader holds it at arm’s length. On the web, the same headline has to survive a phone in a bus and a monitor across a desk. Specifying type for a screen is less about choosing sizes and more about writing the rules that choose them for you.
Size the display type to the viewport, and the body type to the reader. Headlines scale fluidly; body text stays put. A reader who zooms should get bigger body text, not a headline that eats the screen.
Clamps, not breakpoints
We stopped writing font sizes per breakpoint years ago. Every display size is a single clamp(): a floor that keeps it legible on a phone, a fluid middle tied to the viewport width, and a ceiling so it doesn’t become absurd on a 32-inch screen. Three numbers, one line, no media queries.
/* Display scale — floor, fluid, ceiling */
h1 { font-size: clamp(3.5rem, 8vw, 9rem); }
h2 { font-size: clamp(2.25rem, 4.4vw, 4rem); }
.lead { font-size: clamp(1.25rem, 2.4vw, 2.2rem); }
body { font-size: 17px; } /* fixed on purpose */
The ceiling matters more than the floor. Without it, a hero that looks right on a laptop turns into a billboard on a large display, and the line breaks you approved stop existing. Set the ceiling at the size you signed off on, and let the fluid value only ever approach it.
Optical size is a token
Fraunces has an optical-size axis that runs from 9 to 144. At the small end the letters are sturdy, open, and slightly wide, built to survive a 14-pixel caption. At the large end the contrast sharpens, the hairlines thin, and the italics turn almost calligraphic. Browsers pick a value automatically from the font size, and for most text that is exactly right.
For headlines we override it. We push display type to the top of the axis with a single utility, so the most expressive cut only appears where there is room for it. Used on a 24-pixel label, the same setting would make the hairlines vanish on a standard screen — which is why it lives in a named token and not in a global rule.
/* Display cut — headlines only, never below ~48px */
.opsz-display { font-variation-settings: 'opsz' 144; }
If a type setting only works at one size, give it a name and use it on purpose. Global defaults are for the settings that work everywhere.
“One italic word per headline. Two, and it’s decoration. None, and the page forgets to breathe.”
Italics on purpose
Every headline on our own site carries exactly one italic word, and it is always the word that carries the meaning — chapters, not recent. The italic is not emphasis in the grammatical sense. It is the place the eye lands after reading the line, the word you remember.
The rule sounds rigid, and it is. That is what makes it useful to a team. A junior designer, a copywriter, and a developer can all apply it without a meeting, and the result reads as one voice across a hundred pages.
The measure is not negotiable
Body copy runs at 60 to 70 characters per line, and nowhere wider. On a large screen that leaves a lot of empty space beside the text, and clients often ask us to fill it. We don’t. The empty column is part of the layout — it is where the margin notes live, and where the reader’s eye rests between lines.
None of this is specific to Fraunces. Swap the face, re-measure the optical sizes, keep the four rules: fluid display, fixed body, named exceptions, a measure you defend. The type changes; the specification travels.