Strip the colour, icons and illustrations from almost any app and what is left is text: labels, numbers, messages, headings, paragraphs. This guide teaches you to set that text so it reads effortlessly, from the anatomy of a letter to the line length of a paragraph to the apostrophe in “don’t”. It is the deepest single-subject guide in the course, because type is the one material you will touch in every screen you ever ship.
Name the parts of a letter and explain why x-height, aperture and spacing decide how a face behaves at screen sizes (understand)
Classify a typeface by its structure and predict where it will work and where it will fail (analyse)
Choose a type system for a product: system or custom, which families, how many, and with what licence (evaluate)
Set body text with the right size, leading and measure, and build a type scale of five to seven sizes (create)
Fix the details that separate amateur from professional text: quotes, dashes, figures, tracking, wrapping and truncation (apply)
Make type survive real conditions: user font sizes, Windows rendering, slow font loading, dark mode and Indian scripts (create)
Warm-up: what do you already see?
Before any theory, test your eye. These three questions are a diagnostic, not a grade. If you get them all right, you already notice type; this guide will give you the vocabulary and the numbers behind that instinct. If you miss them, good: you now know exactly what to watch for as you read.
How to study this guide: read one Part per sitting. Do each chapter’s quiz before you move on, and do at least the exercises marked “on your own product”. Keep your own app open in another window the whole time. Typography is learned with the eyes and hands, so every time you read a rule, look for it in your screen and change one thing.
A
Your subscription renews on the first of each month. If you cancel before then, you will keep access until the end of the current period and you will not be charged again. Receipts are emailed to the address on your account and are also available under Settings, Billing, History.
Version A
B
Your subscription renews on the first of each month. If you cancel before then, you keep access until the end of the current period and won’t be charged again. Receipts are emailed to you and live in Settings › Billing.
Version B
Diagnostic 1
Version B above feels easier to read. Which change contributes the most?
Size and leading do most of the work. At 12px with 1.2 line height, lines crowd each other and the eye slips when it returns to the left edge. The serif/sans switch matters far less than people think (Chapter 4), justification at that width causes uneven gaps but is secondary, and shorter copy helps but is a writing fix, not a typographic one.
Diagnostic 2
A dashboard shows a column of prices: ₹1,111.00 above ₹9,990.00. The digits don’t line up vertically even though the column is right-aligned. What is wrong?
In many fonts a “1” is narrower than a “9”. Proportional figures look nice in a sentence but make columns wobble. Tabular figures give every digit the same width, so places align. You will build this in Chapter 13.
Diagnostic 3
Which of these strings is typographically correct for an English UI?
Only D uses curly quotes and apostrophes throughout, an en dash for the range, and a real ellipsis character, and it avoids mixing straight and curly marks. C mixes straight and curly quotes (and uses a spaced en dash where a colon reads better), which is the most common tell of copy pasted from a code editor. Chapter 12 has a fixer you can paste your own strings into.
Part one
Seeing type
Before you can choose or set type well, you need to see it: the parts of a letter, the families typefaces belong to, and what actually happens in a reader’s eyes. These four chapters build the vocabulary every later decision uses.
1
Why type is most of the interface
Taught by Oliver Reichenstein, with Beatrice Warde and Robert Bringhurst
In software, typography is not decoration on top of the design; for most screens it is the design, so getting type right improves every screen at once.
In 2006 Oliver Reichenstein of Information Architects published an essay called “Web Design is 95% Typography”. His argument was simple: the overwhelming majority of what people consume on the web is written language, so the core skill of a web designer should be shaping written information. Twenty years on, the claim holds for products too. Look at a to-do app, a banking app, a settings screen or a code editor and count the pixels that are text versus everything else. Text is the interface.
This has a practical consequence for you as a solo creator. Type decisions are the highest-leverage design decisions you can make, because they are global. Change the body size, leading and colour once in your CSS or your SwiftUI text styles, and every screen improves. Polish one illustration and one screen improves. If you have limited time (you do), type is where to spend it first.
Delete everything but the words and the screen still works. Delete the words and nothing works. Hierarchy, grouping and meaning in most product screens are carried by type: size, weight, colour, position.
The crystal goblet
In a 1930 lecture later published as “The Crystal Goblet”, the typographer Beatrice Warde compared good typography to a clear glass: a wine lover wants a goblet that reveals the wine, not an ornate gold cup that hides it. Her point was that type in the service of reading should be invisible. The reader should notice the meaning, not the letters.
That idea is the north star for product typography, with one adjustment. In a product, type has two jobs. In reading mode (an article, a note, a long description) it should disappear. In interface mode (labels, buttons, numbers, headings) it should be instantly scannable, which means it must create clear differences: this is a heading, that is a label, this number matters more than that one. Good product typography is invisible in the first job and quietly structured in the second.
Typography exists to honor content.Robert Bringhurst, The Elements of Typographic Style
What “good” looks like on a screen
Bringhurst wrote for books, Matthew Butterick (Practical Typography) translated much of it for the web, and both agree on the goal: text that respects the reader’s time and attention. On a screen that comes down to five testable qualities, which the rest of this guide unpacks one by one:
Comfortable body text. Big enough, with enough line spacing, at a line length the eye can track (Chapter 7).
Clear hierarchy with few means. A small set of sizes and weights, each with a job (Chapters 8 and 9).
Consistent rhythm. Spacing that follows a system, so related things sit together (Chapter 10).
Correct details. Real quotes, proper dashes, aligned figures (Chapters 12 to 14).
Robustness. Text that survives long names, large user font sizes, slow networks, Windows rendering and other scripts (Part five).
Don't
Every line shouts in a different voice. Five families, no order. The eye has nowhere to start.
Do
One family, two weights, three sizes. The number leads, the label explains, the action waits.
Key idea
Type is the one design decision that touches every screen. Fix it globally first, and decorate later, if ever.
For the solo creator
You likely design in code. That is an advantage: your type system can live in a dozen lines of CSS custom properties or a single Swift file of text styles, and every component inherits it. Spend your first design hour of any project on those dozen lines. They will outlive most of your other decisions.
Do
Treat type settings as global tokens you set once and reuse.
Judge a screen by squinting: can you still see the order?
Let content decide: read the real text before styling it.
Don't
Use type to decorate when it should inform.
Set sizes ad hoc per component (“this one looks better at 15px”).
Design with lorem ipsum; real words have real lengths and rhythms.
In the wild
iA WriterInformation Architects, 2010
Almost no chrome: the product is a single, carefully set column of text in a custom typeface derived from IBM Plex Mono. Users pay for how the text feels. When type is right, it can be the whole product.
Things 3Cultured Code, 2017
Uses Apple’s system font and builds its calm look almost entirely from size, weight, grey values and generous spacing. You don’t need a custom font to look crafted; you need a disciplined system.
KindleAmazon, 2007 to today
Amazon commissioned Bookerly (Dalton Maag, 2015) specifically for reading on its screens, and gives readers control of size, margins and line spacing. For a reading product, typography is the core feature, not a skin.
Common mistakes
Polishing visuals while body text is 13px grey on white
Illustrations and gradients are fun and visible in screenshots; body text feels boring.
Audit body text first: size, contrast, leading, measure. It is the bulk of what users look at.
Type decided component by component
Each screen is built in isolation, so each gets “whatever looked fine”.
Define named text styles (body, small, label, title, heading, display) before building screens, and refuse new ones without a reason.
Check yourself
You have one free afternoon to improve the look of your note-taking app. Which change will be noticed on the most screens?
Body text appears on almost every screen of a notes app, and these three settings are global. The others each touch a few screens and don’t change how the product reads.
Exercise 1.1 30 minutes · on your own product
The text-only screenshot
Take screenshots of three key screens of your product.
In any editor, cover every non-text element (icons, images, colour fills) with a flat grey box.
For each screen, write one sentence: can a stranger still tell what is most important, what is secondary and what is clickable?
List the type-only fixes that would restore any lost order (size, weight, colour, spacing).
You're done when: you have three masked screenshots and a list of at least five type fixes, ranked by how many screens each would touch.
Beginner
Competent
Strong
Masked screens, vague notes (“looks messy”).
Specific fixes per screen (“title and label are both 15px semibold”).
Fixes expressed as global rules (“one title size; labels always muted 13px”), ranked by reach.
2
The anatomy of type
Taught by Erik Spiekermann, with Matthew Carter and Tobias Frere-Jones
A few measurable parts of a letter (x-height, aperture, contrast, spacing) predict almost everything about how a typeface will behave at screen sizes.
You don’t need to draw type to design with it, but you do need to see it. Spiekermann’s Stop Stealing Sheep & Find Out How Type Works exists because most people look at letters and see only “nice” or “not nice”. Designers see parts. Once you can name the parts, you can predict behaviour: this face will blur at 12px, that one will look huge at 16px, this one will turn grey and weak in dark mode.
The five horizontal guides. Cap height and x-height are the two that matter most on screens. The ratio between them is where the “size” of a typeface really lives.
Baseline
The invisible line letters sit on. Round letters (o, e) dip slightly below it (overshoot) so they look aligned with flat ones.
x-height
The height of lowercase letters without ascenders, like x, a, e. Because most reading happens in lowercase, x-height determines how big a face looks. Two faces at 16px can differ by 15% or more in apparent size.
Cap height
The height of flat capitals like H. Cap height matters for aligning text to icons and for all-caps labels.
Ascender and descender
The parts of b, d, h, k, l that rise above the x-height, and of g, j, p, q, y that drop below the baseline. Long extenders help word recognition but need more line spacing.
Stem
The main vertical stroke, like the uprights of H or the spine of l. Stem thickness defines weight.
Bowl and counter
The bowl is the curved stroke enclosing a space (in b, d, o, p). The counter is the enclosed or partly enclosed space itself. Small counters fill in with ink, or with blur on low-resolution screens.
Aperture
How open a partly enclosed counter is, in c, e, a, s. Open apertures keep letters distinct at small sizes.
Terminal
The end of a stroke that has no serif, like the top of a or the end of c. It can be ball-shaped, sheared, flat or tapered.
Serif
The small foot or cap at the end of a stroke. Sans serif means without.
Contrast
The difference between thick and thin strokes. High contrast looks elegant in print and large sizes; at small screen sizes the thin strokes can vanish.
Sidebearings and spacing
The built-in space on each side of a glyph. Spacing is as much part of the design as the shapes; loose spacing reads better small, tight spacing looks better large.
Why x-height matters on screens
Screens are lower resolution than print. A 16px letter on a typical display has its x-height drawn with roughly 7 to 9 pixels. Every pixel of x-height you gain makes counters bigger and shapes more distinct. That is why faces designed for screens, such as Verdana and Georgia (Matthew Carter, 1996, made for Microsoft when screens were coarse), have large x-heights and generous spacing. It is also why a classical book face like Garamond looks small and spindly at the same nominal size: its x-height is modest and its strokes are thin.
The px value is not the size you see. When you swap fonts, re-tune the size by eye. A face with a small x-height may need 18–20px to read like another face at 16px.
Why aperture matters
Aperture is the most underrated screen-legibility feature. In a closed-aperture face (Helvetica is the classic example), the ends of c, e, a and s curl back towards each other. That looks tidy and uniform at large sizes. At small sizes, or with blur, motion or low vision, those letters start to look like o. Humanist sans serifs (Frutiger, Source Sans, Fira) keep the apertures open, so each letter stays itself.
Schematic, not a real typeface. Look at a, c, e, s in any font you are considering. If the strokes nearly touch, test it hard at your smallest UI size.
Contrast, terminals and other screen risks
High-contrast faces (Didot, Bodoni, Playfair Display) have hairline thin strokes. At 48px on a headline, gorgeous. At 14px on a Windows laptop, the hairlines fall below one pixel and break up. Low-contrast faces with sturdy strokes survive. Similarly, tiny distinctions like the difference between l (lowercase L), I (capital i) and 1 (one) are fine in a novel, where context resolves them, and dangerous in a password, a promo code or a file name. Atkinson Hyperlegible (Braille Institute, 2019) was designed specifically to exaggerate such distinctions for low-vision readers.
Don't
Il1 O0 rn m
Code: Il1lO0 (which is which?)
Ambiguous glyphs. Fine in prose, dangerous in codes, IDs and passwords.
Do
Il1 O0 rn m
Codes in IBM Plex Mono: Il1lO0
Distinct shapes. Use a face with a tailed l, serifed I and slashed or dotted zero wherever characters must be copied.
For the solo creator
Keep a one-line test string in your notes: Il1 O0 rn m a c e s 3 8 B. Paste it into any font you consider, at your smallest UI size, on the worst screen you own. Thirty seconds, and it catches most screen-legibility problems before you commit.
Do
Compare faces by x-height, not by nominal px.
Prefer open apertures and moderate contrast for UI and small text.
Use hairline, high-contrast display faces below about 24px.
Assume 16px means the same size across fonts.
Judge a face from its marketing specimen at 72px.
In the wild
Verdana & GeorgiaMatthew Carter for Microsoft, 1996
Designed for the coarse CRT screens of the 1990s, with large x-heights, wide spacing and shapes that hold up when drawn in few pixels. Screen faces are built around the pixel, not adapted to it.
RetinaFrere-Jones Type, for The Wall Street Journal
A face for tiny financial tables, drawn with wide proportions and ink traps so numbers stay distinct at very small sizes. Small text needs a face designed for small text.
Atkinson HyperlegibleBraille Institute, 2019
Exaggerated letterform differences (tailed l, slashed zero, distinctive b/d/p/q) for low-vision readers; free to use. Distinctness is a design parameter you can choose.
Common mistakes
Using a print book face for UI
It looked beautiful in a specimen at 60px.
Test at 12–16px on a non-Retina screen. Prefer faces with a screen heritage or explicit optical sizes for small text.
Swapping fonts without re-tuning size
The design tokens stay at 16px, but the new font has a 10% smaller x-height.
After any font swap, re-tune body size and line height by eye against the old version.
Ambiguous characters in codes
Recovery codes and licence keys are set in the UI font.
Use a monospace with distinct glyphs, or remove ambiguous characters from the alphabet you generate codes from.
Check yourself
Your app shows 2FA backup codes like “lO8Il1” to users who must type them on another device. People report codes “not working”. Best fix?
The failure is glyph ambiguity between l, I, 1, O and 0. A face that distinguishes them helps, and removing them from the alphabet fixes it at the source. Bold and spacing don’t change the shapes; a high-contrast serif makes it worse.
Exercise 2.1 40 minutes · on fonts you use daily
Anatomy field notes
Pick three typefaces: your product’s UI font, the font of an app you love reading in, and one display face you admire.
Type “Handgloves Il1 O0 aces” in each at 64px and at 13px.
For each, note: x-height (small, medium, large relative to cap height), aperture (open or closed), contrast (low, medium, high), and anything that breaks at 13px.
Write one sentence per face predicting where it belongs: body, UI labels, headings only, or nowhere in your product.
You're done when: you have a small table of three faces × four properties, and a usage prediction for each.
Beginner
Competent
Strong
Properties noted, but no link to usage.
Each prediction follows from a property (“closed aperture, so not for 12px labels”).
Predictions tested by setting a real screen at both sizes and confirmed or corrected.
3
Classification: families of form
Taught by Robert Bringhurst, with Erik Spiekermann
Typefaces fall into families defined by how their strokes were made; knowing a face’s family tells you its voice, its era and how it behaves on screen before you test it.
Classification is not trivia. Each category comes from a tool and a period: the broad-nib pen of Renaissance scribes, the engraver’s steel, the industrial sign painter, the geometric ideals of the Bauhaus. Those origins left fingerprints in the shapes (where the stress falls, how much contrast there is, how open the letters are), and those fingerprints are exactly what determine screen behaviour. Learn ten categories and you can read a new typeface the way a sommelier reads a label.
Ten families, ten fingerprints. Look at the “a” and “g”: two-storey and pen-shaped in old style, rounder and more uniform as you move to neo-grotesque and geometric. If fonts fail to load, your system substitutes similar faces.
The serif families
Old style faces come from the broad-nib pen, which makes thick and thin strokes depending on angle. The thinnest parts of an o sit on a diagonal (the “stress”). Contrast is modest, serifs are bracketed (they curve into the stem), and the whole thing feels warm and literary. They read well in long text, but classic old-style revivals often have small x-heights, so give them more size on screen.
Transitional faces (eighteenth century) straightened the stress towards vertical and sharpened the details. Times New Roman belongs here, and it was drawn for narrow newspaper columns, which is why it is compact.
Didones pushed contrast to the extreme: hairline serifs, vertical stress, ball terminals. Luxurious at magazine-cover sizes; fragile at text sizes on screens.
Slab serifs have thick, rectangular serifs and low contrast. Born for posters, they now include sturdy text faces (Roboto Slab, Zilla Slab) that hold up well on low-quality screens because nothing in them is thin.
The sans serif families
Grotesques were the first commercial sans serifs: slightly irregular, with some stroke contrast. Neo-grotesques (Helvetica, Univers) smoothed them into neutral, uniform shapes with horizontal terminals that curl in, which closes apertures. Humanist sans serifs bring back pen proportions and open apertures (Gill Sans, Frutiger, Myriad, Source Sans), and tend to be the most legible at small sizes. Geometric sans serifs build letters from circles and straight lines (Futura, Avenir, Jost); they are clean and stylish, but their perfectly round o, c, e and single-storey a can blur together in body text.
Most modern UI faces are hybrids. Inter is broadly neo-grotesque but with taller x-height and slightly more open forms tuned for screens. SF Pro sits between neo-grotesque and humanist. Don’t worry about precise labels; use the categories to predict behaviour.
Category
Voice
Good on screen for
Risks
Old style
Literary, warm, bookish
Long reading at 18px+
Small x-height, thin details at 12–14px
Transitional
Formal, established
Articles, editorial headings
Times is narrow and dated as a UI default
Didone
Fashion, luxury
Big headlines only
Hairlines vanish at small sizes and in dark mode
Slab
Sturdy, mechanical, friendly
Headings, e-reader text, robust UI
Can feel heavy in dense UI
Grotesque
Honest, slightly gritty
Headings, editorial UI
Quirks can distract in labels
Neo-grotesque
Neutral, modern, corporate
UI, dashboards
Closed apertures at tiny sizes; can feel bland
Humanist sans
Friendly, clear
UI, small text, signage-like labels
Less “crisp” feeling than neo-grotesques
Geometric
Stylish, optimistic
Brand, headings, short text
Round letters blur in long text
Monospace
Technical, typewriter
Code, IDs, aligned data, writing tools
Wide; uneven texture in prose
Display
Loud, specific
One big word
Unreadable as text
Don't
Your order has shipped. Track the parcel from the Orders page, and contact us if anything looks wrong with the delivery address.
A Didone at 13px. Hairlines flicker and break; the paragraph looks grey and spotty.
Do
Your order has shipped. Track the parcel from the Orders page, and contact us if anything looks wrong with the delivery address.
A humanist sans at 15px. Even strokes, open shapes, calm texture. Save the Didone for a 40px heading if you need its voice.
Key idea
Origins predict behaviour: pen-made faces read warmly, engraved ones sparkle big and break small, geometric ones look great and read slower.
For the solo creator
You don’t need a library of fonts. Pick one sans that is good at small sizes (humanist or a screen-tuned neo-grotesque) and, only if your product involves long reading, one serif designed for screens. That covers 95% of products. Spend the saved hours on spacing.
Do
Choose by behaviour (size, aperture, contrast) first and voice second.
Use high-contrast and display faces only at large sizes.
Expect modern UI faces to be hybrids; test rather than label.
Don't
Pick a geometric sans for long body text because it looks modern.
Pair two faces from the same category (two neo-grotesques fight).
Use a display face for anything longer than a few words.
In the wild
Medium2012 onward
Long-form posts are set in a serif at a generous size (around 20px) with a sans serif for UI and metadata. Serif for reading, sans for interface is a pattern because it works, not because it is a rule.
AirbnbCereal, 2018
A custom geometric-leaning sans gives the brand a friendly, rounded voice across app and marketing. Geometric faces carry brand personality; product teams then tune size and spacing for legibility.
GitHubSystem fonts, 2017
Switched its UI to the operating system’s font stack, with a monospace for code and later custom faces (Mona Sans, Hubot Sans) for marketing. Neutral UI, distinctive voice elsewhere.
Common mistakes
Choosing by mood board
The face fit the brand vibe in a 120px hero image.
Shortlist by voice, then eliminate by behaviour: set your real UI at 12, 14 and 16px and keep only what survives.
Monospace for everything
It feels “developer”, so it goes on buttons, headings and paragraphs.
Keep monospace for code, IDs and deliberate writing-tool contexts (see Chapter 18). Prose in monospace is wide and uneven.
Check yourself
You are building a calm reading app for long essays. Which pairing is most likely to work?
Long reading wants sturdy, moderate-contrast text forms designed for screens; the UI wants a clear sans with open shapes. A Didone breaks at body sizes, two neo-grotesques look like a mistake, and monospace body text is a deliberate niche choice, not a default.
Exercise 3.1 30 minutes · on apps you use daily
Classify your home screen
Open five apps you use daily. For each, identify the UI typeface (screenshots plus a font-identifier tool, or the browser inspector for web apps).
Place each in a category from the table above.
Note one place where the face’s family helps (or hurts) the product’s job.
You're done when: you have five rows: app, face, category, one observation about fit.
Beginner
Competent
Strong
Faces named, categories guessed.
Categories justified by visible traits (stress, aperture, terminals).
Observations link traits to the product’s job and suggest a better alternative where fit is poor.
4
Legibility, readability and how eyes read
Taught by Kevin Larson (reading research), with Walter Tracy and Keith Rayner
Reading is a series of quick jumps and short stops; typography helps when it makes each stop easy (legibility) and each jump predictable (readability).
Two words that people use interchangeably mean different things. In Walter Tracy’s classic distinction, legibility is about the typeface: how easily individual characters can be told apart. Readability is about the setting: how comfortably a block of text can be read for a long time, which depends on size, spacing, line length, contrast and layout. A highly legible face can be set unreadably (8px, justified, 140 characters wide), and a modest face set with care can read beautifully.
Setting beats selection. Most products already use a legible face. What they get wrong is size, spacing and length, which is good news: those are free to fix.
What the eyes actually do
Your eyes do not glide along a line. They make rapid jumps called saccades and brief stops called fixations. Eye-movement research summarized by Keith Rayner gives typical figures for skilled readers of English: fixations last around a quarter of a second, saccades jump around seven to nine characters, and somewhere around 10–15% of saccades go backwards (regressions) to re-check something. During a fixation you only see detail in a small window, a few letters to the left and more (roughly 14–15 characters) to the right. At the end of each line comes the return sweep, a long jump back to the start of the next line, which is where readers most often lose their place.
Reading is jumping. Measure (line length) and leading (line spacing) exist mainly to make the return sweep reliable, which is why they matter so much (Chapter 7).
The word-shape myth
For decades designers repeated that we read by recognizing the outline of whole words (the “bouma”), and that this is why lowercase reads faster than all caps. In 2004 Kevin Larson of Microsoft’s advanced reading team published a review, The Science of Word Recognition, arguing that the evidence points elsewhere: readers recognize the letters within a word in parallel and use that information to identify the word. All-caps text is slower mostly because we have far less practice reading it, and alternating-case text slows people down because it disrupts letter recognition, not just outline.
Why this matters for you: it means letter distinctness (Chapter 2) is what you are designing for. Don’t justify all-caps paragraphs by saying “outline doesn’t matter”, and don’t justify tiny lowercase by saying “people read shapes anyway”. Make letters clear, words well spaced, and lines easy to track.
Design for letters. Clear, distinct letterforms and good spacing are what help readers, as reviewed by Larson (2004).
Myth
“Serif is more readable in print, sans serif on screens.” Studies comparing serif and sans for reading speed and comprehension have mostly found small or no reliable differences once size and spacing are matched. On today’s high-density screens the old pixel argument against serifs has largely gone. Choose by voice, x-height, contrast and setting, not by the serif/sans rule.
Familiarity is a feature
Readers read fastest what they read most. That is a quiet argument for conventional choices: sentence case over all caps, mixed case over small caps for long text, familiar letterforms over quirky ones (a single-storey a or a playful g may charm in a logo and slow down a paragraph). Novelty costs attention. Spend it where you want attention, never in body text.
Don't
Your trial ends in three days. Choose a plan to keep your projects, or export everything as Markdown from Settings.
All caps paragraph. Slower to read because it is unfamiliar, and it reads as shouting.
Do
Trial
Your trial ends in three days. Choose a plan to keep your projects, or export everything as Markdown from Settings.
Caps only for a short label. Sentence case for the message, tracked caps for a two-word tag (Chapter 14).
For the solo creator
You can’t run eye-tracking studies, and you don’t need to. Read your own long screens aloud at normal speed. Wherever you stumble, lose your place or re-read, mark it. Those are your regressions and failed return sweeps, and the fix is almost always size, leading or line length.
Do
Separate “is the face legible?” from “is the setting readable?”
Design for return sweeps: moderate line length, enough leading.
Prefer familiar letterforms and sentence case for anything longer than a label.
Don't
Repeat the word-shape theory as a design rule.
Argue serif versus sans while body text is 13px.
Set paragraphs in all caps or small caps.
In the wild
Microsoft ClearType researchLate 1990s to 2000s
Microsoft’s reading research group studied how rendering and type affect reading on screens, work connected to ClearType rendering and the ClearType font collection that shipped with Windows Vista (Calibri, Cambria, Consolas and others). Screen reading is a solvable engineering problem, not just taste.
Apple Books & Kindle2010s–today
Both let readers choose a font, size and line spacing, accepting that comfort varies by person and eyesight. For long reading, give control; your defaults are a starting point.
UK GOV.UKGovernment Digital Service
Uses sentence case almost everywhere, short line lengths and plain sizes, with research behind the style guide. Familiar, unshowy setting serves the widest audience.
Common mistakes
Blaming the font
Text feels hard to read, so the font must be wrong.
Before swapping fonts, try +2px size, line-height 1.5 and a 65-character measure. Most “bad fonts” are bad settings.
Caps for emphasis in sentences
It feels like the strongest way to make something stand out.
Use weight (semibold) for emphasis in UI, italics in prose. Keep caps for very short labels.
Check yourself
Users of your docs site say long pages are tiring; they keep losing their place. Body is Inter 15px, line-height 1.3, column 1100px wide. What do you change first?
“Losing their place” is a return-sweep failure: lines are far too long (1100px at 15px is around 160 characters) and leading is tight. The face is fine. Fix the setting.
Connect the ideas · Part one recap
In The Human Mind you met limited attention. Which typographic choice best respects it in a busy settings screen?
Attention is spent on novelty and decoding. A familiar face with a few clear steps lets users spend attention on the settings, not the letters. The others add decoding cost (caps, display faces) or noise (multiple voices).
Exercise 4.1 25 minutes · on your own product
The read-aloud audit
Pick the longest piece of text in your product (help article, onboarding, a long note, a description).
Read it aloud at a normal pace from the screen, finger off the trackpad.
Mark every stumble: lost line, re-read, squint, skipped word.
For each mark, decide: is it legibility (a letter or glyph problem) or readability (size, leading, measure, contrast, alignment)?
You're done when: you have a marked-up screenshot and a count of legibility versus readability problems, plus one setting change you will test.
Beginner
Competent
Strong
Stumbles marked.
Each stumble classified correctly as legibility or readability.
Proposed change tested and the read-aloud repeated with fewer stumbles.
Part two
Choosing type
With the vocabulary in place, you can make the first real decision: which typefaces your product uses, how many, and under what licence. For most solo products the right answer is smaller and cheaper than you expect.
5
Choosing typefaces for a product
Taught by Matthew Butterick, with Rasmus Andersson and Oliver Reichenstein
Start from the system font and only leave it for a reason you can name; when you do leave it, choose a face built for screens that covers every size, weight, figure style and script you need.
Every font choice is a trade between three things: fit (does it suit your product’s job and voice), function (does it behave at your sizes, with your numbers, in your languages), and cost (licence, file size, loading time, maintenance). Designers new to type over-weight fit. Experienced ones start with function and cost, and let fit choose between the survivors.
Option one: the system font
Each platform ships a superb UI family: SF Pro on Apple platforms (since 2015), Segoe UI on Windows (Segoe UI Variable on Windows 11), Roboto on Android (since 2011, redesigned in 2014). On the web you reach all of them with one CSS stack, and you pay nothing in download size.
What you get for free is easy to underestimate. Apple’s SF switches between Text and Display designs (and, in recent versions, uses a variable optical-size axis) and adjusts tracking by size automatically. System fonts support the platform’s Dynamic Type or text scaling. They cover many scripts, they are hinted for each platform’s renderer, and they make your app feel native because they are what everything else on the device uses.
What you give up: distinctiveness (you look like everyone), and cross-platform consistency (your web app will have slightly different widths on Mac, Windows and Android, so layouts must flex). A known wrinkle: on some Windows language settings, system-ui can resolve to a font you didn’t expect, which is one reason some teams list named fonts instead.
Option two: a chosen family
Choose a specific family when you have a reason: long reading where a serif voice matters, a brand that needs a distinctive voice, tabular data that needs particular figure features, or the need for identical metrics across platforms. Then hold the face to a function checklist before you fall for it.
A default decision path. Most solo products end at the first or last box. Leave them only for a reason you can write in one sentence.
The function checklist
Before committing to any face, check that it has: at least regular, medium or semibold, and bold (four weights is comfortable; a variable font is better); true italics if you set prose; tabular and lining figures (Chapter 13); the punctuation and symbols you use (₹, €, arrows, ×, curly quotes); every script your users write in; good hinting or rendering on Windows if you have Windows users; and a licence that covers how you ship (web, app, ePub, video).
Good free families for screens
Family
Origin
Best for
Notes
Inter
Rasmus Andersson, 2017
Dense UI, dashboards, numbers
Tall x-height, many OpenType features (tabular figures, slashed zero, alternates), variable; a Display optical size arrived with version 4
IBM Plex
IBM with Bold Monday, 2017
Products that need sans, serif and mono that match
Superfamily with several scripts, including Devanagari, Arabic and others
Source Sans 3 / Source Serif 4
Adobe (Paul D. Hunt; Frank Grießhammer)
Humanist UI, readable serif
Source Serif 4 has an optical-size axis; this page’s body text uses it
Literata
TypeTogether for Google Play Books
Long reading on screens
Designed for e-reading; variable with optical sizes since version 3
Charter
Matthew Carter, 1987
Sturdy, compact body serif
Built for low-resolution output; freely licensed; Butterick recommends it as a good free serif
iA Writer Mono / Duo / Quattro
Information Architects, from IBM Plex Mono
Writing tools, focused editors
Duo widens a few letters (m, w and friends) to soften monospace’s unevenness; Quattro goes further toward proportional; open licence
Atkinson Hyperlegible
Braille Institute, 2019
Accessibility-first products, codes
Exaggerated letter differences for low-vision readers
Lexend
Bonnie Shaver-Troup, Thomas Jockin
Reading-support contexts
Width variants designed around reading-proficiency research by its creators; treat claims as promising, not proven
Public Sans
U.S. Web Design System
Neutral, civic, government-like UI
Derived from Libre Franklin; strong, plain, free
Noto
Google
Coverage for nearly every script
Use as a fallback or as the main family for multilingual products
Lab: shortlist tester
Il1 O0 rn m · aces 38B · ₹1,234.50
NotificationsDaily summary
Your draft was saved two minutes ago. Changes sync across devices when you are online, and earlier versions stay in History for 30 days.
Drop the size to 12px and switch between Inter, Jost and Playfair. Watch the test string and the paragraph: which faces keep l, I and 1 apart, and which turn grey and spotty? That is your shortlist filter.
Don't
Fighting the platform. A custom face inside native chrome looks off next to the status bar and system sheets, and loses Dynamic Type.
Do
Belonging. In native UI, the system face is the voice users trust. Express brand in content, icon and colour instead.
Key idea
Function and cost decide the shortlist; taste decides between the survivors.
For the solo creator
A good rule: native app, use the system font and its text styles, full stop. Web app, start with the system stack; switch to one open-licence family (self-hosted, subset, variable) only if you can say in one sentence what it does that the system font doesn’t. Every family you add is something you maintain forever.
Do
Check weights, italics, figures, symbols, scripts and licence before falling in love.
Test at your smallest real size on Windows and on a phone.
Prefer variable fonts to cut files and get in-between weights.
Don't
Ship SF Pro as a webfont; its licence restricts it to Apple platforms. Use system-ui instead.
Pick a family missing ₹, curly quotes or your users’ script.
Choose a face because a famous brand uses it.
In the wild
Linear2019 onward
Built its dense, crisp UI on Inter, a free screen family with tall x-height and tabular figures. A free, well-engineered family can carry a premium-feeling product.
Google Play BooksLiterata, 2015
Commissioned a reading face from TypeTogether instead of using the UI font for book text. Reading and interface are different jobs and may deserve different faces.
Things 3, Apple NotesApple platforms
Both use the system font and system text styles, and both scale with the user’s preferred text size. Native apps gain more from the system face than any custom font could give.
Common mistakes
Custom font in a native app
It is the easiest way to feel “branded”.
Use system text styles in native apps; if you must use a custom face, scale it with the platform’s font metrics APIs so it still respects user text size.
Missing glyphs discovered in production
You tested with English placeholder copy.
Keep a test string with ₹ € × → “ ” ’ – … and a line in each script you support. Check every candidate face against it.
Too many weights loaded
“Just in case”, nine static weights and their italics ship to every visitor.
Load one variable file, or two to three static weights you actually use. Audit with the browser’s network panel.
Check yourself
You are building a cross-platform web app for invoices used by small shops in India. Which choice is soundest?
Invoices are numbers and names: tabular figures, the rupee sign and Indian scripts are functional requirements. SF Pro can’t legally ship as a webfont, a geometric sans often lacks the features, and multiple fonts add cost and noise.
Exercise 5.1 60 minutes · on your own product
Write your type decision record
List your product’s text jobs: UI labels, body or long text, numbers or tables, code or IDs, headings or brand.
For each job, write the minimum function requirement (sizes, figures, scripts, weights).
Shortlist up to three candidates (including the system font) and test each with the shortlist lab above and your real screens.
Write a half-page decision: chosen faces, the jobs each does, what you rejected and why, licence, and how it is loaded.
You're done when: you have a one-page type decision record you could hand to a future you in a year.
Beginner
Competent
Strong
A chosen font with a reason like “it looks clean”.
Requirements listed and checked; rejections explained.
Decision covers loading, licence, fallbacks and scripts, and was tested on Windows and at user-enlarged sizes.
6
Pairing, superfamilies and licences
Taught by Erik Spiekermann, with Matthew Butterick
One family is usually enough; when you pair, combine clear contrast in structure with shared proportions, and give each face a distinct job.
Pairing advice is full of folklore (“always pair a serif with a sans”). The underlying logic is simpler. Two faces on one screen should either be clearly the same (one family) or clearly different (contrasting structure). The failure zone is in between: two faces that are almost alike, so the reader senses a difference but can’t tell what it means. That reads as a mistake.
Be clearly same or clearly different. Nearly-alike faces send a signal with no meaning.
Rules that actually explain pairings
Start with one family. A good family with three or four weights and italics gives you more hierarchy than most products need (Chapter 9).
If you pair, contrast structure. Serif with sans, or a display face with a text face. Not two neo-grotesques.
Share proportions. Faces with similar x-height ratio and width sit comfortably on the same line and in adjacent blocks. Mismatched x-heights make one look shrunken.
Share an era or a construction logic when possible. A humanist sans (pen proportions) pairs naturally with an old-style or modern humanist serif. A geometric sans sits well with a didone or a geometric slab.
Give each face a job. “Serif for reading, sans for interface” or “display for page titles only”. If you can’t state a face’s job, you don’t need it.
Prefer superfamilies. IBM Plex, Source, Noto and Roboto (Roboto, Roboto Slab, Roboto Mono, Roboto Serif) were designed to work together, with matched metrics. The pairing work is already done.
Match apparent size. When two faces share a line or a screen, size them by x-height. The CSS property font-size-adjust does this numerically for fallbacks and mixed faces.
Don't
Monthly summary
You saved ₹4,200 this month, mostly on groceries. Your largest expense was rent.
Inter heading, Plex body. Two similar grotesques: the reader feels a shift but it carries no meaning.
Do
Monthly summary
You saved ₹4,200 this month, mostly on groceries. Your largest expense was rent.
One family, two weights. Hierarchy from size and weight alone. Simpler, faster to load, more coherent.
Licensing basics
A font is software, and its licence says where you may use it. You will meet four common situations:
Licence
What it allows
Watch for
SIL Open Font License (OFL)
Use, embed in apps and websites, modify and redistribute, including commercially. Most Google Fonts, Inter, IBM Plex, Source, Literata, iA Writer fonts, Atkinson Hyperlegible.
You can’t sell the font on its own. “Reserved Font Names” mean a modified version must be renamed.
Apache 2.0
Similar freedoms; some Google families were released under it, including the original Roboto.
Keep the licence notice with the files.
Commercial (desktop, web, app, ePub)
Separate licences per use: desktop for making designs, web by pageviews or domains, app by number of apps or installs.
A desktop licence does not let you embed the font in your app or on your website.
Platform fonts (SF Pro, Segoe UI)
Use through the OS. Apple’s SF licence covers designing and developing for Apple platforms.
Don’t ship them as webfonts or in non-platform builds; reference them via system font stacks.
Hosting also matters. Loading fonts from a third-party CDN sends your visitors’ IP addresses to that service; in 2022 a German court found that embedding Google Fonts from Google’s servers without consent violated GDPR. Self-hosting open-licence fonts avoids the issue and is usually faster anyway (Chapter 16).
Watch out
“Free for personal use” fonts from download sites are not free for your product. If the licence isn’t OFL, Apache or a commercial licence you bought for your use case, don’t ship it.
For the solo creator
Keep a /fonts/LICENSES folder in your repo with each font’s licence file and a one-line note: where it came from, version, what it covers. It takes five minutes and saves a frightening afternoon if a buyer, an app store reviewer or a lawyer ever asks.
Do
Try one family first; add a second only with a named job.
Pair across structure with similar proportions.
Keep licence files with font files and self-host open fonts.
Don't
Pair two similar sans serifs or two similar serifs.
Use three or more families in product UI.
Assume “free download” means free to embed.
In the wild
IBM PlexIBM, 2017
Sans, Serif, Mono, condensed widths and many scripts in one open superfamily, so products can mix them without pairing problems. Superfamilies remove pairing risk.
NotionPage styles
Lets users switch a page between Default (sans), Serif and Mono styles, each a single coherent voice rather than mixed fonts. Offer voices, not font soup.
The GuardianGuardian Egyptian, 2005
A single custom family with headline and text cuts in serif and sans styles (Paul Barnes and Christian Schwartz) gives the paper its voice across print and digital. A designed family is the professional answer to pairing.
Common mistakes
Near-miss pairings
You liked one font for headings and another for body, and both are clean sans serifs.
Pick one of them for both roles, and create contrast with weight and size.
Font from a template, licence unknown
A UI kit or theme came with fonts bundled.
Identify every font in your build and find its licence; replace anything unclear with an OFL equivalent.
Check yourself
Your landing page uses Playfair Display for the hero, Inter for UI, Lora for testimonials and Roboto for the footer. What is the best move?
A display face for one job plus one workhorse is a strong, simple system. Four families are noise (Inter and Roboto are near-identical in role), and a Didone for everything breaks at small sizes.
Connect the ideas · Part two recap
Recall Chapter 2 (anatomy). You pair Literata body text with a geometric sans for captions, and captions look tiny next to the body even at the same px. Why, and what fixes it?
Apparent size lives in the x-height (Chapter 2). Geometric sans often have smaller x-heights than screen serifs. Size by x-height, not by px.
Exercise 6.1 45 minutes · on your own product
Pairing audit and licence folder
List every font family your product ships (inspect the network tab or your bundle).
Write each family’s job in one sentence. Any family without a clear job is a candidate for removal.
If you have two faces on one screen, set them side by side on one baseline and adjust sizes until x-heights relate deliberately.
Create a licence folder with each font’s licence and source.
You're done when: your product uses one or two families with written jobs, sizes are x-height matched, and every font has a licence on file.
Beginner
Competent
Strong
Fonts listed.
Jobs written, one redundant family removed or planned for removal.
X-heights matched, licences filed, and bundle size measured before and after.
Part three
Setting text
Choosing a face is a one-time decision. Setting it is what you do on every screen: size, line spacing, line length, a scale of sizes, hierarchy, rhythm and alignment. This Part is the heart of the guide, and it has the most labs. Use them; the numbers become intuition only through your eyes.
7
Size, leading and measure
Taught by Robert Bringhurst, with Matthew Butterick
Body text reads best at 16–20px on screens, with line-height around 1.4–1.6, on lines of 45–75 characters; and the three numbers depend on each other.
These are the three settings that decide whether a paragraph is comfortable. They are not independent. A bigger size needs a longer line in px to keep the same characters per line. A longer line needs more leading so the return sweep (Chapter 4) can find the next line. A face with a tall x-height looks bigger and needs more leading than one with a small x-height. Tune them together.
Size: start at 16, often go higher
Browsers default to 16px, and that is a floor for body text on the web, not a target. Butterick suggests 15–25px for web body text; many reading-focused sites sit at 18–21px. On iOS the default Body text style is 17pt; Android’s Material body sizes are around 14–16sp. People hold phones closer than they sit to laptops, so similar numbers work on both. Text smaller than about 12–13px should be rare and never essential.
Leading: the space between lines
“Leading” comes from the strips of lead typesetters put between lines of metal type. In CSS it is line-height, best written unitless (1.5, not 24px) so it scales with size. For body text, 1.4–1.6 is the usual band; Butterick suggests 120–145% of the point size, and WCAG’s enhanced criterion asks for at least 1.5 within paragraphs. Use the low end for short lines and small x-heights, the high end for long lines and tall x-heights. Headings need less: 1.1–1.25, because large sizes already create space and loose headings fall apart into separate lines.
Measure: characters per line
Bringhurst gives the classic range: 45 to 75 characters per line (counting letters and spaces) for single-column text, with around 66 often cited as ideal. Shorter lines force constant return sweeps and choppy reading; longer lines make the sweep long and error-prone. In CSS set it with max-width in em or ch. Note that ch is the width of the digit zero, which is usually wider than an average letter, so 66ch typically gives somewhat more than 66 real characters. Test with real text, as the lab below does.
Too long
Lost return sweeps. The eye overshoots or repeats lines.
Comfortable
Easy rhythm. Lines short enough to sweep, spaced enough to land.
Reading is not a smooth glide. Your eyes jump a few words at a time, pause for a fraction of a second, and at the end of every line make a long sweep back to the left edge to find the next one. When lines are too long, that sweep misses; when they are packed too tightly, the target is too small to hit. Comfortable text is not about a beautiful font so much as about three numbers chosen together: how big the letters are, how much air sits between the lines, and how many characters each line carries before it turns.
Characters per line: –Line height: –Suggested for this measure: –
Try this: set width to 900px and line-height to 1.2, then read the paragraph. Now bring width down until the counter says about 65, raise line-height to the suggestion, and read again. Then switch to EB Garamond and notice you want 2px more size for the same comfort. (On a phone the screen limits the width, which is the point: phones naturally produce 35–45 characters.)
Leading relative to measure
The lab’s suggestion follows a simple principle: the longer the line, the more leading it needs. A 40-character mobile column can live at 1.4; a 75-character desktop column wants 1.6 or more. Text with a tall x-height (Inter, Atkinson, Verdana) looks tighter at the same line-height, because the gap between lines (from baseline to the next line’s x-height) is smaller; give it 0.05–0.1 more.
A rule of thumb, not a law. Roughly +0.1 of line-height for every 15–20 extra characters per line. Then adjust by eye for the face’s x-height.
Paragraph spacing or indent, never both
Paragraphs need a signal that a new one has begun. Either add space between them (on screens, typically 0.75–1em, smaller than a full blank line is fine), or indent the first line (1–2em) with no extra space, as books do. Using both double-signals and wastes space. On screens, and especially in UI and documentation, spacing is the norm because text is scanned as much as read. First-line indents suit continuous reading like fiction and long essays.
Don't
The parcel left the warehouse this morning and is with the courier now.
You will get a message when it is out for delivery.
Indent plus space. Two signals for one job.
Do
The parcel left the warehouse this morning and is with the courier now.
You will get a message when it is out for delivery.
Space only. The screen convention: calm, scannable blocks.
Key idea
Size, leading and measure are one decision with three dials. Move one, re-check the other two.
For the solo creator
Write three tokens and use them everywhere: --text-body: 1.125rem (18px), --leading-body: 1.55, --measure: 34em. Put max-width: var(--measure) on every container of running text, not on the page. The page can be wide; paragraphs shouldn’t be.
Do
Use unitless line-height so it scales.
Limit running text to 45–75 characters, measured with real text.
Tighten leading for headings (1.1–1.25).
Don't
Let paragraphs stretch across a 1440px monitor.
Set body text below 16px on the web to “fit more”.
Inherit body line-height (1.5) into 40px headings.
In the wild
WikipediaVector 2022 skin
The 2022 redesign introduced a maximum width for article content after years of full-width text on large monitors. Even the web’s biggest reference work found that limiting line length helps reading.
Instapaper & Reader modes2008 onward
Reading modes in Instapaper, Safari Reader and others strip a page and re-set it with a larger size, generous leading and a narrow column. People install products just to fix size, leading and measure.
iA WriterInformation Architects
Keeps the writing column at a comfortable measure and scales type with the window, so line length stays reasonable across devices. Line length can be a product feature, not just a style.
Common mistakes
Full-width text on desktop
The layout was built mobile-first and the container simply grows.
Cap text containers with max-width in em or ch; let images and tables go wider if needed.
Leading in px
Copied from a design tool that shows line-height in px.
Convert to unitless ratios; px leading breaks when the user or a component changes font size.
One line-height for everything
A global line-height: 1.5 on body is inherited by headings.
Set line-height per text style: body 1.5–1.6, UI labels 1.3–1.4, headings 1.1–1.25.
Check yourself
Your help center article is set at 17px, line-height 1.5, in a 720px column of Inter. The counter shows about 88 characters per line. Readers find it tiring. Which fix keeps the layout and improves reading most?
88 characters is too long. Narrowing to about 34em brings it near 65–70. Dropping the size makes lines even longer in characters; justification and weight don’t touch the real problem.
Exercise 7.1 45 minutes · on your own product
Set your body text tokens
Find the longest real paragraph in your product and paste it into the readability lab (or a local HTML file).
Choose your face, then find the smallest size you can read comfortably for five minutes. Add 1px.
Set measure to 60–70 characters and choose line-height from the suggestion, then adjust by eye.
Write the three tokens into your codebase and apply them to all running text containers.
You're done when: your product has body size, leading and measure tokens, applied everywhere text runs longer than two lines, with before/after screenshots.
Beginner
Competent
Strong
Values copied from this chapter.
Values tuned by eye with real text, applied globally.
Values tested on phone, laptop and a large monitor, with a mobile variant (smaller measure, slightly tighter leading).
8
Type scales: a few sizes, related
Taught by Tim Brown (modular scales), with Robert Bringhurst
Pick five to seven sizes related by a consistent ratio, give each a job, and use nothing else; the relationship between sizes is what makes hierarchy feel intentional.
Look at a product built without a scale and you’ll find 11px, 12px, 13px, 14px, 15px, 16px, 17px, 18px, 20px, 22px, 24px and 28px, each chosen once for one component. The result looks slightly off everywhere, because neighbouring sizes are too close to read as different levels and too far to read as the same. A scale fixes this by making every size a deliberate step.
Modular scales
Bringhurst described the classical scale of sizes used by printers since the sixteenth century, and in 2011 Tim Brown’s article “More Meaningful Typography” (A List Apart) and his modularscale.com tool popularised the idea for the web: start with a base size and multiply by a ratio. With a 16px base and a 1.25 ratio you get 16, 20, 25, 31.25, 39 and so on; dividing gives 12.8 and 10.24 below. The ratios have musical names because they are the same intervals:
Ratio
Name
Feel
Good for
1.125
Major second
Very gentle steps
Dense apps, dashboards, mobile
1.2
Minor third
Gentle, quiet
Most product UI
1.25
Major third
Clear but calm
Docs, content apps, general web
1.333
Perfect fourth
Confident
Editorial sites, blogs
1.5
Perfect fifth
Dramatic
Landing pages, marketing
1.618
Golden ratio
Very dramatic
Posters, hero sections; too steep for apps
The ratio sets the drama. Steep ratios produce memorable headlines and very few usable steps; gentle ratios give many close steps for complex UI.
Lab: type scale generator
/* CSS tokens appear here */
Six named steps are generated from your base. Faded rows are sizes you probably don’t need. Copy the tokens into your stylesheet. Try 1.5 with base 16 and see how quickly sizes become too big for an app screen; then try 1.2.
How many sizes you really need
Most products work with five to seven sizes: caption or small, body, a large body or subtitle, two or three heading levels, and possibly one display size for marketing. Material Design 3 defines fifteen named roles (display, headline, title, body and label, each in large, medium and small), and Apple’s iOS text styles define eleven (from Large Title at 34pt down to Caption 2 at 11pt, with Body at 17pt). Notice that Apple’s steps aren’t a strict ratio: they are hand-tuned, with tighter steps in the text range and bigger jumps at the top. That is a good model. Use a ratio to generate candidates, then round and adjust.
Apple’s hand-tuned scale (default “Large” setting, points). Close steps in the text range, a big leap to Large Title. Users can scale all of these together.
Fluid scales
On the web, a heading that is right at 1440px is often too big at 375px. You can use a gentler ratio on small screens and a steeper one on large screens, interpolating with CSS clamp(): for example font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem) for a page title. Keep body text nearly fixed (it should not shrink on phones) and let display sizes flex.
Don't
Sizes too close. Each is different, none reads as a level.
Do
Fewer, further apart. Same-level items share a size; weight and colour do the rest.
Key idea
A scale is a vocabulary. Small vocabularies are easier to speak consistently.
For the solo creator
Name sizes by role, not by number: --text-small, --text-body, --text-title, --text-heading, --text-display. Then a design change (“body up one step”) is one edit, and you can’t accidentally invent a 15.5px.
Do
Generate sizes from a ratio, then round and hand-tune.
Use gentle ratios (1.125–1.25) in apps, steeper ones in marketing.
Keep five to seven sizes, each with a named job.
Don't
Introduce a new size to fix one component.
Use adjacent sizes 1px apart for different levels.
Use the golden ratio for an app because it sounds principled.
In the wild
Apple HIG text stylesiOS, iPadOS
Eleven named styles that scale together with Dynamic Type. Developers pick a role (Headline, Body, Footnote), not a size. Roles survive redesigns and user scaling; raw sizes don’t.
Material Design 3Google, 2021
Fifteen roles in five groups, with tokens for size, line-height, weight and tracking per role. A type role is a bundle: size, leading, weight and tracking travel together.
Tailwind CSSDefault theme
Ships a fixed set of named sizes (text-xs to text-9xl), each paired with a default line-height. Even utility-first CSS works from a closed scale.
Common mistakes
Scale with too many steps in use
The generator outputs ten sizes, so all ten get used.
Generate many, adopt few. Delete unused tokens so they can’t creep in.
Size carries every level
The only tool used for hierarchy is size, so the scale needs many close steps.
Use weight and colour for minor distinctions (Chapter 9); reserve size changes for real level changes.
Check yourself
You’re designing a dense analytics app used on laptops. Which scale is most sensible?
Dense UIs need gentle steps and a slightly smaller base, with hierarchy from weight and colour too. The golden ratio explodes past usable sizes; 12px base is too small for comfortable reading; per-widget sizing creates drift.
Exercise 8.1 60 minutes · on your own product
Collapse your sizes
List every font size in your codebase (search CSS for font-size or your text style definitions). Count them.
Use the generator to create a scale from your body size with a ratio that fits your product type.
Map each existing size to the nearest scale step, and name each step by role.
Refactor, then compare before/after screenshots of three screens.
You're done when: your product uses at most seven named sizes, and the before/after count is written down (for example “14 sizes → 6”).
Beginner
Competent
Strong
Scale generated, partly applied.
All text uses named steps; count reduced by half or more.
Steps hand-tuned, line-height and weight defined per role, fluid display sizes on web.
9
Hierarchy without shouting
Taught by Massimo Vignelli, with Erik Spiekermann
Size is only one of six levers for typographic hierarchy; calm interfaces use weight, colour, case, space and position for most distinctions, and change only one or two levers per level.
Vignelli was famous for working with very few typefaces and a few sizes, and still producing rich, clear hierarchy. The trick is that hierarchy is about difference, and size is the loudest, most space-hungry way to make a difference. In a dense product screen you have many small distinctions to make (title vs metadata, label vs value, active vs inactive), and if all of them use size you end up with a dozen sizes and a noisy page. See Visual Design for hierarchy in layout; this chapter covers the typographic levers.
Six levers. Size and weight add emphasis; colour and space subtract it. Most UI hierarchy can be built from weight and colour alone, at one or two sizes.
Emphasis by subtraction
Beginners make important things bigger and bolder. Experienced designers more often make unimportant things quieter: smaller, lighter, muted grey. The effect is the same contrast, but the page gets calmer instead of louder. A list item with a 15px semibold title and a 13px muted line of metadata has clear hierarchy without any big type.
Be careful with grey. Muted text still has to meet contrast requirements (4.5:1 for normal text under WCAG AA); “subtle” #AAA on white fails. Use one or two defined text colours (primary and secondary), not a gradient of greys. See Accessible & Inclusive for the contrast details.
Hierarchy by size vs hierarchy by weight and colour
Invoices
Acme Studio
INV-2041 · Due 12 March
₹48,000
Lotus Bakery
INV-2040 · Paid
₹6,250
Northwind Ltd
INV-2039 · Overdue
₹1,12,500
Invoices
Acme Studio
INV-2041 · Due 12 March
₹48,000
Lotus Bakery
INV-2040 · Paid
₹6,250
Northwind Ltd
INV-2039 · Overdue
₹1,12,500
Without: everything is big and bold, so nothing stands out. Five sizes and three weights compete. The overdue invoice is invisible.
With: two sizes. Names are semibold, metadata muted, the section label a tracked overline. Now the one thing that matters (overdue) is the only coloured, emphasized item.
Weights: fewer than you think
Two weights (regular and semibold, or regular and bold) handle most interfaces. Add medium only if your face’s regular looks thin at small sizes. Light and thin weights are for large display sizes; at 14px on a Windows laptop they disappear. Avoid “faux bold”: if you set font-weight: 600 but haven’t loaded a 600 weight, the browser smears the regular glyphs to fake it, and the result is blotchy.
Italics and emphasis
In prose, emphasis is italic (a quiet change in texture that doesn’t break the line’s colour). In UI, emphasis is weight, because italics in short labels look accidental. Underline is reserved for links on the web, and colour alone is never the only signal (some users can’t see it).
Don't
Remember: never share your recovery key with anyone, including our support team.
Every lever at once. Bold, underline, caps and italics in one sentence cancel each other out.
Do
Never share your recovery key with anyone, including our support team.
One emphasis, where it surprises. The surprise is “including support”, so that is what gets italics.
Key idea
Make the important things clear by making everything else quieter.
For the solo creator
Define exactly two text colours (--text and --text-secondary) and two weights (400 and 600). Try to build every new screen with only these plus your scale. When you feel the urge for a third grey or a bold-italic, treat it as a sign the content structure needs work, not the type.
Do
Use weight and colour for minor levels, size for major ones.
Mute secondary information rather than shouting primary.
Load the real weights you set in CSS.
Don't
Stack bold, caps, colour and underline on one phrase.
Use light or thin weights for small text.
Use more than two greys for text.
In the wild
Apple Mail & GmailInbox lists
Unread messages are shown mainly by weight (bold sender and subject), not by size, so read and unread rows keep the same rhythm. Weight changes state without breaking the layout.
Stripe DashboardTables and detail views
Detail views pair small labels with regular-weight values and muted secondary lines, building dense but calm screens from very few sizes. Overlines and muted metadata replace headings in dense UI.
Vignelli’s NYC Subway manualUnimark, 1970
A tightly limited palette of type sizes and one family for an entire signage system. Constraint makes a system learnable.
Common mistakes
Everything is bold
Each element was emphasized when it was built, in isolation.
Start every screen at regular weight; add semibold only to the one item per group the eye should land on first.
Grey that fails contrast
Light grey looks elegant on a good monitor.
Check secondary text at 4.5:1 or above; if it fails, darken it and use size or weight to separate instead.
Check yourself
In a task list, completed tasks need to recede and overdue tasks need to stand out. All rows are 15px regular. What is the calmest effective treatment?
State is a minor level; colour and a small label handle it without breaking row rhythm. Size changes, caps and font swaps are loud tools for a quiet job.
Exercise 9.1 40 minutes · on your own product
One size, many levels
Pick your busiest list or card screen.
Rebuild it (in code or a quick mock) using a single font size for all text in the list rows. Use only weight, colour, case and space to create hierarchy.
Compare with the original. Where did you need size? Add it back only there.
You're done when: you have a version with at most two sizes in the list and clear hierarchy, plus a note on which distinctions truly needed size.
Beginner
Competent
Strong
Single-size version made but hierarchy unclear.
Clear hierarchy from weight and colour; contrast checked.
Shipped, with fewer sizes and weights than before and no loss of clarity in a quick test with someone else.
10
Vertical rhythm and spacing
Taught by Robert Bringhurst, with Josef Müller-Brockmann
Space between text elements should come from a small set of related values, and space above a heading should be larger than space below it, so headings belong to what follows.
Bringhurst compares the page to music: the rhythm of lines and spaces should be steady, and departures from it should be meaningful. In print, typographers lock every line to a baseline grid so lines on facing pages align. On screens, a strict baseline grid is harder (and less valuable), but the underlying idea is essential: spacing should be systematic, and it should express relationships.
The heading proximity rule
A heading labels the content below it, so it should sit closer to that content than to the content above. A common ratio is about 2:1 (for example 32px above, 12–16px below). When the spaces are equal, the heading floats ambiguously between two sections, and users have to read it to know where it belongs. This is the Gestalt principle of proximity (see The Human Mind) applied to type.
Don't
Equal spacing. The heading floats between sections.
Do
More above, less below. Proximity does the grouping.
A spacing system from your line-height
The simplest rhythm on screens: derive spacing from a base unit (commonly 4px or 8px) and keep line-heights on that unit too. If body text is 18px with line-height 1.5, a line is 27px, which doesn’t sit on a 4px grid; 18px × 1.556 ≈ 28px does. Many teams round line-heights in px to multiples of 4 for each text style (body 28, small 20, title 32, heading 40) and use spacing tokens of 4, 8, 12, 16, 24, 32, 48, 64. Then everything snaps to one invisible rhythm and nothing looks “a bit off”.
A grid of 28px rows. Strict baseline grids are useful for long reading pages; for app UI, consistent spacing tokens give most of the benefit with less fuss.
Why exact baseline grids are hard on the web
CSS centres text inside its line box: half the extra leading goes above, half below (“half-leading”), and the font’s own ascent and descent metrics add more invisible space. So the visible top of a capital letter is not at the top of the box. That is why a button label can look slightly low even when padding is “equal”, and why aligning text to an icon needs care. Tools such as Capsize compute trims from font metrics, and newer browsers support the text-box properties (text-box-trim and text-box-edge) that cut the box down to cap height and baseline. Use them for precise component alignment; don’t chase a perfect page-wide baseline grid in a complex app.
Invisible space around text. It is why “equal padding” often looks unequal. Trim it when precise alignment matters (buttons, icon rows, badges).
For the solo creator
Don’t build a baseline-grid framework. Do this instead: spacing tokens on a 4px base, line-heights per text style rounded to 4px, and the 2:1 heading rule. Turn on a 4px grid overlay in your browser dev tools once a month and look for strays.
Do
Put more space above headings than below.
Use a small set of spacing tokens tied to a base unit.
Trim text boxes (or nudge) when aligning text with icons.
Don't
Use arbitrary margins like 13px or 22px.
Let heading margins equal paragraph margins.
Force a rigid baseline grid onto dense, mixed-size UI.
In the wild
Material Design4dp/8dp grid
Components and type line-heights are designed to snap to a 4dp baseline, with spacing in 8dp steps. A shared unit for type and layout keeps a huge system consistent.
GOV.UK Design SystemSpacing scale
Publishes a responsive spacing scale and uses consistent heading margins across thousands of pages. Rhythm can be enforced with tokens, not willpower.
CapsizeSeek, open source
Uses font metrics to trim the space above capitals and below the baseline, so text boxes align precisely to layout. Invisible metric space is a solvable engineering detail.
Common mistakes
Margins on both sides of everything
Each component brings its own top and bottom margin, and they stack unpredictably.
Use a layout-level rule (for example a stack with gap, or margin only on top of following siblings) so spacing comes from one place.
“Equal padding” that looks unequal
Text line boxes include invisible ascent and descent space.
Judge visually, or trim with text-box/Capsize; adjust by 1–2px if needed.
Check yourself
In your docs, section headings have 24px margin above and 24px below. Users skim and sometimes read the wrong section. Best fix?
The problem is grouping: equal spacing makes headings float. Proximity fixes it without adding visual noise. Rules on both sides would make it worse by boxing the heading off from its content.
Exercise 10.1 40 minutes · on your own product
Spacing census
On one long screen, measure every vertical gap between text elements (dev tools or a screenshot ruler).
List the unique values. Map each to a token on a 4px base.
Fix heading spacing to roughly 2:1, refactor gaps to tokens, and compare before/after.
You're done when: the screen uses only spacing tokens, headings follow the proximity rule, and you have before/after screenshots side by side.
Beginner
Competent
Strong
Gaps measured.
All gaps tokenized, heading rule applied.
Tokens adopted product-wide, with line-heights rounded to the base unit.
11
Alignment, rag and wrapping
Taught by Matthew Butterick, with Robert Bringhurst
On screens, set text flush left and ragged right by default; justify only with good hyphenation and a generous measure, and let the browser balance headings and avoid stranded last words.
Justified text, with both edges straight, looks orderly in books because book typesetting engines adjust spacing across a whole paragraph, hyphenate carefully, and may even subtly adjust letter spacing. Browsers mostly do something simpler: they break lines one at a time and stretch the word spaces on each line to fill it. On narrow columns, that produces irregular gaps and sometimes “rivers”, channels of white that run down through the paragraph and pull the eye vertically.
Rivers come from stretched spaces. Ragged right keeps word spacing constant, which is what the eye actually relies on.
When justification is fine
Justified text can work on screens when three conditions hold: the measure is generous (60+ characters), hyphenation is on (hyphens: auto with a correct lang attribute on the page or element), and the content is continuous reading (an e-book, a long essay) where a book-like texture is part of the experience. E-readers such as Kindle justify by default with hyphenation. For UI, docs and anything narrow or mixed with code and links, ragged right is better. WCAG’s enhanced criterion (1.4.8) lists “not justified” among its visual presentation requirements, because uneven spacing makes reading harder for some people, including many dyslexic readers.
Lab: justified vs ragged, with hyphenation
Typographers have argued about justification for centuries. In a well-made book, the compositor balances spacing across the whole paragraph and hyphenates carefully, so the texture stays even. Browsers typically break lines one at a time and stretch the spaces, which in narrow columns opens irregular gaps and occasionally a river of white running down the page. Hyphenation helps, because breaking long words gives the line breaker more choices. Characteristically, administrative, internationalization and responsibility are the kind of words that cause trouble.
Start at 300px, justified, hyphenation off: look for big gaps. Turn hyphenation on and watch them shrink. Then widen to 600px and notice justification becomes acceptable. “Pretty” wrapping (where supported) avoids a single stranded word on the last line.
Shaping the rag
Ragged right isn’t carefree. A good rag ripples gently; a bad one has deep notches or a staircase shape. On the web you can’t hand-tune each paragraph, but you can help: keep the measure in range, enable hyphenation for long-word languages (German, Dutch) and narrow mobile columns, and use non-breaking spaces to keep small units together (“10 MB”, “Mr. Sharma”, “Chapter 7”).
Widows, orphans and stranded words
In print, an orphan is a paragraph’s first line left alone at the bottom of a page and a widow is its last line alone at the top of the next (definitions vary between sources, which is why many people just say “stranded lines”). On the web, the everyday problem is a single short word alone on the last line of a paragraph or heading (sometimes called a “runt”). CSS now helps: text-wrap: balance evens out line lengths in short blocks like headings and captions, and text-wrap: pretty asks the browser to avoid very short last lines in paragraphs. Balance is widely supported; pretty is newer, so treat both as progressive enhancement.
Don't
Your notes, exported to Markdown or PDF in seconds
Unbalanced heading. Full lines, then a stub (“seconds”) alone on the last.
Do
Your notes, exported to Markdown or PDF in seconds
text-wrap: balance. Lines of similar length; the heading reads as one shape.
Centred and right-aligned text
Centred text has two ragged edges, so every return sweep must find a new starting point. It works for short, symmetrical things (a dialog title, a two-line empty state, a poster headline) and fails for anything over about three lines. Right alignment is for numbers in tables (Chapter 13) and for labels hugging a value, not for paragraphs (in left-to-right languages).
Key idea
The eye trusts even word spacing more than straight edges. Keep the spaces even; let the edge breathe.
For the solo creator
Three lines of CSS cover most of this chapter: h1,h2,h3{text-wrap:balance}, p{text-wrap:pretty}, and html{lang} set correctly so hyphenation and quotes work when you need them. Add hyphens:auto only on narrow mobile columns or long-word languages.
Do
Default to left aligned, ragged right.
Balance headings and avoid stranded last words.
Use non-breaking spaces between numbers and units.
Don't
Justify narrow columns without hyphenation.
Centre paragraphs longer than three lines.
Fix rag by inserting manual line breaks that break on other screens.
In the wild
KindleAmazon
Justifies book text with hyphenation by default, and some Kindle devices and apps let readers switch to left alignment. Justification is a book convention; offering ragged is a kindness.
GitHub, Notion, LinearDocs and issues
All set long text flush left, ragged right, in UI-width columns. Product text is mixed (links, code, mentions); ragged handles it gracefully.
Chrome & Safari2023–2024
Shipped text-wrap: balance, making balanced headings a one-line fix that previously needed JavaScript libraries. Check the platform before writing a workaround.
Common mistakes
Justified text on mobile
The desktop design was justified and nobody checked a 360px phone.
Use ragged right below a breakpoint, or never justify in UI at all.
Manual line breaks in headings
A <br> made the heading look perfect on your screen.
Remove it; use text-wrap: balance so the break adapts to every width.
Check yourself
You are building an e-reader for long novels and want a book-like feel. Which setting is most defensible?
Book-like justification needs hyphenation and enough measure; a ragged option respects readers who find uneven spacing harder. Unhyphenated or narrow justification creates rivers, and centring breaks return sweeps.
Connect the ideas · Part three recap
A blog post is 17px, line-height 1.3, 100 characters per line, justified, with 9 sizes in use. You have 30 minutes. In which order do you fix it?
Measure and leading (Chapter 7) affect every line read, so they come first. Switching to ragged right (this chapter) is a one-line fix with high value. Collapsing the scale (Chapter 8) matters but is a larger refactor. The face is usually last (Chapter 4).
Exercise 11.1 30 minutes · on your own product
Wrap and rag pass
Add text-wrap: balance to headings and text-wrap: pretty to paragraphs in your product.
Find every centred or justified block longer than three lines and decide: keep (with reason) or change to left aligned.
Search your copy for numbers followed by units and insert non-breaking spaces where a break would hurt.
You're done when: headings are balanced, no long paragraph is centred, and you have before/after screenshots at 360px and 1280px.
Beginner
Competent
Strong
CSS added.
Alignment audited and fixed product-wide.
Also checked in a second language or a long-word test string, with hyphenation set appropriately.
Part four
The details
Readers rarely notice correct punctuation, aligned figures or well-tracked capitals. They do notice, often without knowing why, when these are wrong: text looks cheap, numbers look jittery, labels look cramped. These chapters are small fixes with outsized effect on perceived quality.
12
Quotes, dashes and the small marks
Taught by Matthew Butterick, with Robert Bringhurst
Straight quotes, double hyphens and three dots are typewriter substitutes; real typography uses curly quotes, true apostrophes, the right dash for each job and a real ellipsis, except in code, where straight characters are correct.
Typewriters had a limited keyboard, so one key served for opening quotes, closing quotes, apostrophes, feet and inches. Computers inherited that keyboard. Butterick calls straight quotes and apostrophes the most visible sign of careless typography, because they look like what they are: a mechanical compromise. Your product’s microcopy is read millions of times. Getting these marks right costs almost nothing once you know them.
Six pairs to learn by sight. Once you see them, straight quotes in a polished UI will bother you forever. That is the point.
The dashes
There are three common horizontal marks and they are not interchangeable. The hyphen (-) joins words (“well-known”, “sign-in page”) and breaks words at line ends. The en dash (–), about the width of an n, marks ranges and connections: “9–5”, “Mumbai–Pune”, “pages 12–18”. The em dash, about the width of an M, marks a strong break in a sentence (shown in the figure above). Many writers overuse the em dash; in UI copy, a colon, comma or full stop is often clearer. The minus sign (−) is a fourth mark, as wide as a plus sign, for negative numbers in data: −₹1,200 lines up with +₹1,200, while a hyphen looks short and weak.
Spaces you didn’t know existed
A non-breaking space ( , U+00A0) looks like a normal space but forbids a line break, so “10 MB”, “₹ 500” (if you space it), “Fig. 3” and “iOS 18” never split across lines. A thin space (U+2009) is useful around some marks and between number groups in some locales. One space after a full stop, never two; the double space is another typewriter habit.
Mark
Use
Mac
Windows
HTML
“ ”
Double quotes
Option+[ , Option+Shift+[
Alt+0147, Alt+0148
“ ”
‘ ’
Single quotes, apostrophe (’)
Option+] , Option+Shift+]
Alt+0145, Alt+0146
‘ ’
–
En dash: ranges
Option+Hyphen
Alt+0150
–
(em)
Em dash: breaks
Option+Shift+Hyphen
Alt+0151
—
…
Ellipsis
Option+;
Alt+0133
…
×
Multiplication, dimensions
Character Viewer
Alt+0215
×
′ ″
Feet, inches, minutes
Character Viewer
Character Map
′ ″
−
Minus sign
Character Viewer
Character Map
−
In source code and string files you can also simply paste the Unicode characters; modern toolchains handle UTF-8. On iOS and many keyboards, long-pressing the quote or hyphen key offers these characters.
Lab: quotes and dashes fixer
Highlighted characters were changed. The fixer uses context: a quote after a space opens, after a letter it closes; a quote after a digit becomes a prime; a hyphen between digits becomes an en dash. It is a teaching tool with simple rules (it will misjudge some cases, such as phone numbers), which is exactly why you should know the rules yourself.
Where straight quotes are correct
Code, terminal commands, JSON, CSS, URLs and anything a user will copy into a technical context must keep straight quotes and hyphens. A curly quote in a shell command breaks it, and an en dash in a command-line flag fails silently. In your product, turn off smart punctuation in code inputs, password fields and API key fields (on iOS, smartQuotesType = .no and smartDashesType = .no; on the web, keep such content in <code> and don’t run text transforms on it).
Don't
Install the CLI:
npm install –g “rohit-cli”
“Smart” punctuation in a command. The en dash and curly quotes break the command when pasted.
Do
Install the CLI:
npm install -g "rohit-cli"
Code stays literal. Monospace, straight characters, in a code element that no text processor touches.
Other languages, other marks
Quote styles vary: German uses „low-high“ quotes, French uses «guillemets» with spaces inside, Japanese uses 「corner brackets」. Hindi text generally uses the same curly quotes as English. If you localize, don’t hard-code quote characters in templates; let translators include them in strings, or use the HTML <q> element with the CSS quotes property and a correct lang attribute.
For the solo creator
Do one pass now: search your UI strings for ", ', --, ... and digit-hyphen-digit, and fix them. Then add a lint rule or a pre-commit script that flags straight quotes in your strings file (not in code). Ten minutes of tooling saves you from ever thinking about it again.
Do
Use curly quotes and apostrophes in all user-facing prose.
Use en dashes for ranges and the minus sign for negative numbers.
Keep code and commands strictly straight.
Don't
Use a hyphen for ranges (“5-10”).
Type three periods for an ellipsis in UI strings.
Let autocorrect curl quotes in code fields.
In the wild
Apple platformsSmart Punctuation
iOS and macOS curl quotes and convert double hyphens as you type, with a setting to turn it off and APIs for developers to disable it per field. Make correct punctuation the default, and give technical fields an escape.
SmartyPantsJohn Gruber, 2002
A widely used text filter that converts straight quotes, double hyphens and triple dots into typographic punctuation, alongside Gruber’s Markdown. Automate punctuation at the content pipeline, then trust it.
Butterick’s Practical TypographyOnline book
Devotes short, blunt chapters to straight and curly quotes, hyphens and dashes, and the ellipsis. The cheapest upgrade to any text is correct punctuation.
Common mistakes
Mixed straight and curly quotes
Some strings came from a design tool (curly), others typed in a code editor (straight).
Normalise all user-facing strings in one pass and lint them.
Backwards apostrophes
Auto-curling sees a quote after a space and opens it: ‘90s instead of ’90s.
Leading apostrophes in abbreviations (’90s, ’n’) always point like a 9 (a closing quote).
Curly quotes in copy-paste commands
A CMS or Markdown filter “smartened” everything, including code.
Exclude code spans and blocks from typographic filters, and test by pasting commands into a terminal.
Check yourself
Which string is correct for a pricing page?
A uses an en dash for the range, curly double quotes, a curly apostrophe and a real ellipsis. B uses a hyphen, a straight apostrophe and three dots; C has spaced hyphen and straight quotes; D fakes double quotes with two single quotes.
Exercise 12.1 30 minutes · on your own product
Punctuation sweep
Export or open your product’s user-facing strings (a strings file, i18n JSON or your templates).
Search for ", ', --, ... and [0-9]-[0-9]. Fix each in prose; leave code alone.
Add non-breaking spaces between numbers and units.
Add a simple lint (a script or regex in CI) that warns on straight quotes in strings.
You're done when: a search for straight quotes in user-facing strings returns only intentional cases, and a lint prevents regressions.
Beginner
Competent
Strong
Main screens fixed by hand.
All strings fixed; code and inputs excluded correctly.
Lint in place, plus smart punctuation disabled in technical input fields.
13
Figures, small caps and OpenType features
Taught by Tobias Frere-Jones, with Edward Tufte and Rasmus Andersson
Most good fonts hide several versions of their numerals and other alternates; choose tabular lining figures for data, proportional or old-style figures for prose, and use real small caps and fractions instead of fakes.
Numbers are everywhere in products: prices, dates, counts, durations, versions. Fonts usually include at least two sets of digits, and many include four, selected with OpenType features. Using the right set is one of those details that makes an interface feel engineered rather than assembled.
Four figure styles. The lining row uses Source Serif 4; the old-style row uses Georgia, whose default figures are old-style (if Georgia isn’t installed, you’ll see lining figures there too). Lining figures sit at cap height; old-style figures rise and fall like lowercase letters, so they blend into prose. Note that font services often strip features like old-style figures when subsetting, so check the files you actually serve.
Tabular vs proportional
Proportional figures have individual widths (a 1 is narrow, a 0 is wide), which looks even in a sentence. Tabular figures all share one width, so digits line up in columns and a changing number (a timer, a progress counter, a stock price) doesn’t jiggle as it updates. In CSS: font-variant-numeric: tabular-nums. Fonts differ in their defaults: Inter defaults to proportional figures (tabular are one feature away), while the Google Fonts versions of Source Serif 4 and EB Garamond default to tabular. Check yours.
Figures in a table: proportional vs tabular
Item
Qty
Amount
Hosting
1
₹1,111.00
Domains
11
₹9,980.50
Fonts
4
₹0.00
Design tools
12
₹14,400.00
Total
₹25,491.50
Item
Qty
Amount
Hosting
1
₹1,111.00
Domains
11
₹9,980.50
Fonts
4
₹0.00
Design tools
12
₹14,400.00
Total
₹25,491.50
Without: proportional figures, left-aligned. Decimal points wander; you can’t compare magnitudes at a glance.
With: tabular lining figures, right-aligned. Places and decimals line up; the eye compares lengths instantly. Same font, two CSS declarations.
Numbers in tables: the rules
Right-align numeric columns (and their headers), so units, tens and hundreds stack. Left-align text columns.
Use the same number of decimal places down a column.
Use tabular lining figures. Consider a slightly smaller size or muted colour for units and currency symbols.
Format by locale. In India, ₹1,12,500 (lakh grouping); elsewhere 112,500 or 112 500 or 112.500. Use Intl.NumberFormat (web) or the platform’s formatters rather than hand-rolled commas.
Use the minus sign (−) for negatives so they align with the plus sign and look like maths.
OpenType features are switches inside a font. The ones worth knowing, with their CSS:
Feature
CSS
Use it for
Tabular figures (tnum)
font-variant-numeric: tabular-nums
Tables, timers, counters
Old-style figures (onum)
font-variant-numeric: oldstyle-nums
Numbers within long prose in serif text
Slashed zero (zero)
font-variant-numeric: slashed-zero
Codes, IDs, data where 0 vs O matters
Fractions (frac)
font-variant-numeric: diagonal-fractions
Recipes, measurements (1/2 → ½)
Small caps (smcp, c2sc)
font-variant-caps: small-caps / all-small-caps
Acronyms in prose (NASA, PDF), quiet labels
Ligatures (liga, dlig)
font-variant-ligatures
Standard ligatures on by default; discretionary ones rarely
Stylistic sets (ss01…), character variants (cv01…)
font-feature-settings: "ss01"
Alternate glyphs, for example Inter’s alternate digits or single-storey a
True small caps are drawn letters at about x-height with weights that match lowercase. Fake small caps, which browsers synthesize by shrinking capitals when the font lacks them, look thin and pale. If your font lacks smcp, don’t use small caps; use tracked caps at a small size instead (Chapter 14).
Don't
The report was sent as a PDF to NASA and the WHO in 1997.
Full caps acronyms and lining figures in prose. They jump out of the line like shouting.
Do
The report was sent as a PDF to NASA and the WHO in 1997.
Small caps and old-style figures. Acronyms and numbers sit within the texture of the paragraph. (Small caps from Source Serif; the old-style year from Georgia, where installed.)
Key idea
Tabular for things that line up or change; proportional or old-style for things that sit in sentences.
For the solo creator
Add a utility class today: .num{font-variant-numeric:tabular-nums lining-nums}, and put it on every price, count, timer, table cell and chart label. It is the single highest-value line of CSS in this chapter. In SwiftUI, .monospacedDigit() does the same.
Do
Use tabular figures in tables, timers and anything that updates.
Right-align numeric columns and format by locale.
Check which OpenType features your font actually has.
Don't
Let a live counter jiggle with proportional figures.
Use browser-faked small caps or bold.
Hand-format numbers with string concatenation.
In the wild
Apple Clock & StopwatchiOS
The stopwatch uses fixed-width digits so the running time doesn’t shift left and right every hundredth of a second. Anything that ticks needs tabular figures.
InterRasmus Andersson
Documents features like tnum, zero (slashed zero), case-sensitive forms and several character variants, so product teams can tune numbers and ambiguous glyphs without changing fonts. Read your font’s feature list; it’s free capability.
Financial appsZerodha Kite, Robinhood and others
Price lists and order books rely on aligned figures and right alignment so users can scan changes quickly. In data-heavy products, figure style is a usability feature.
Common mistakes
Jiggling counters
The default figures are proportional and nobody tested a live update.
Apply tabular figures to every number that changes on screen.
Feature set on a font that lacks it
The CSS is right, but the loaded font (or subset) doesn’t contain the feature.
Check the font’s features (many foundry pages list them; tools like Wakamai Fondue show them) and keep features when subsetting.
Check yourself
Your pomodoro timer shows 24:59 counting down, and users say it “shakes”. What fixes it?
Proportional digits change width as they tick, so the string’s width changes and it shifts. Tabular figures share a width. Bold, old-style and centring don’t address width changes (centring actually makes the shake symmetric, not gone).
Exercise 13.1 35 minutes · on your own product
The number audit
List every place your product shows numbers: tables, prices, counters, dates, timers, charts.
For each, decide the figure style (tabular lining for data and changing values; default for prose).
Add a .num utility (or platform equivalent) and apply it. Right-align numeric columns and switch formatting to locale-aware APIs.
Record a short screen capture of any live number before and after.
You're done when: every changing or tabulated number uses tabular figures, numeric columns are right-aligned, and numbers are formatted by locale.
Beginner
Competent
Strong
Tabular figures on one table.
All numeric contexts covered; locale formatting in place.
Also uses minus signs, consistent decimals, muted units, and checked the font’s feature support.
14
Tracking, kerning, optical sizes and variable fonts
Taught by Matthew Carter, with Erik Spiekermann and Tobias Frere-Jones
Fonts are spaced for lowercase text at one size range; capitals, very small text and very large text all need spacing adjustments, and optical sizes and variable fonts let the font itself adapt.
A type designer spends as long on spacing as on shapes. The spacing is tuned for lowercase text around reading sizes. Move away from that sweet spot and the spacing stops fitting. Two adjustments fix it: tracking (uniform letter-spacing across a run of text, letter-spacing in CSS) and kerning (adjustments between specific pairs like “AV” or “To”, built into the font and on by default in browsers).
The three tracking rules
All caps and small caps: add tracking. Capitals are designed to sit next to lowercase, so in a row of capitals they crowd. Butterick suggests 5–12% extra; in CSS, letter-spacing: 0.05em to 0.12em. The smaller the caps, the more they need.
Large display text: reduce tracking slightly. At 40px and above, default spacing looks loose. Try −0.01em to −0.03em. Never so tight that letters touch.
Small text: add a touch. Below about 13px, a hair of extra spacing (0.01–0.02em) helps letters stay distinct. Apple’s SF does this automatically by size.
Never track lowercase body text for “style”: it breaks up word shapes and slows reading. And note a CSS detail: when you add letter-spacing, browsers turn off optional ligatures, which is what you want for spaced caps.
At 13px with 0% tracking, the caps look cramped. Slide tracking to 8–10% and they open up into a calm label. Now raise the size to 36px: the same tracking looks too loose, and 2–4% is enough. Tracking needs scale with size in the opposite direction.
Spacing where it’s needed. Caps breathe; lowercase keeps the designer’s spacing.
Optical sizes
In metal type, each size was cut separately: small sizes had larger x-heights, sturdier hairlines, looser spacing; large sizes were finer and tighter. Digital fonts lost that when one outline was scaled to every size. Optical sizes bring it back. Some families ship separate cuts (SF Pro Text and SF Pro Display; Inter and Inter Display), and variable fonts can have an opsz axis that the browser sets automatically from the font size (font-optical-sizing: auto, the default). This page’s body text, Source Serif 4, has an opsz axis: the headings and body you are reading are slightly different designs.
Same font, same size, two designs. Forcing the small optical size onto a big heading exaggerates the difference so you can see it. Normally the browser picks the right one automatically. (If fonts are blocked, both lines look identical.)
Variable fonts
A variable font is one file containing a continuous design space along axes. The registered axes are weight (wght), width (wdth), optical size (opsz), italic (ital) and slant (slnt); fonts may add custom ones, such as grade (GRAD), which changes weight without changing width. For a product this means: one file instead of six, any weight you like (550 if 500 is too light and 600 too heavy), automatic optical sizing, and tricks like adjusting grade in dark mode (Chapter 18). Use font-weight, font-stretch and font-optical-sizing when possible; drop to font-variation-settings only for custom axes.
Continuous axes. Static fonts give you named stops; variable fonts let you choose the point between them. Use this sparingly: a system still needs few, named weights.
Key idea
Caps need air, big text needs less, small text a touch more. Let optical sizes do the rest.
For the solo creator
Put tracking into your text style tokens, never into components: --label-caps: 600 0.75rem/1.3 var(--sans); letter-spacing: .08em, display headings −0.02em, everything else 0. Then nobody (including future you) tracks lowercase body text on a whim.
Do
Track all-caps labels 5–12%.
Tighten large display headings slightly.
Prefer variable fonts with an opsz axis for products with wide size ranges.
Don't
Track lowercase body text.
Turn off kerning (it’s on by default; leave it).
Use one weight of a display cut for small UI text.
In the wild
SF ProApple, 2015 onward
Apple’s system applies size-specific tracking and switches optical designs (Text below about 20pt, Display above), so developers rarely touch letter-spacing. The best tracking is the kind the system does for you.
Inter 42023
Added an optical-size axis and Inter Display, so headings get tighter, finer forms automatically. Open-source fonts now offer what used to need premium families.
Roboto FlexGoogle, 2022
A variable font with many axes including weight, width, optical size and grade. Grade lets you change weight for contrast without reflowing text.
Common mistakes
Tight caps buttons
Text-transform: uppercase was added without tracking.
Whenever you uppercase, add letter-spacing in the same rule.
Negative tracking on body text
It made a marketing headline look sleek, and the token leaked into body styles.
Scope negative tracking to sizes above about 24px only.
Check yourself
Your 11px uppercase section labels look cramped and dark, but your 48px hero headline looks loose. Which settings fit?
Small caps need positive tracking; large display needs slight negative tracking. +0.3em is extreme and makes labels fall apart into letters.
Connect the ideas · Part four recap
A countdown banner reads "SALE ENDS IN 2:09:45 -- don't miss it!" in tight caps. Which combination of fixes from Chapters 12–14 applies?
Caps need tracking (14), a ticking timer needs tabular figures (13), and the double hyphen and straight apostrophe are typewriter marks (12). Sentence case would also read faster (Chapter 4).
Exercise 14.1 30 minutes · on your own product
Tracking tokens
Find every uppercase text in your product (search for uppercase or caps in strings).
Set tracking per size using the lab: small caps around 0.08–0.1em, larger caps around 0.04em.
Find headings above 32px and try −0.01 to −0.02em; compare side by side.
Move all letter-spacing values into text style tokens.
You're done when: no component sets letter-spacing directly, and every caps style has tracking in its token.
Beginner
Competent
Strong
Caps tracked.
Tracking tokenized by size; display headings tightened.
Also adopted a variable font or optical size where available and checked results on Windows.
Part five
Type in the product
Everything so far applies to any text. Products add hard conditions: tiny labels, live numbers, names of unknown length, users who set their text to 200%, Windows laptops, slow networks, Hindi and English on one screen, code, dark mode. This Part makes your type robust, and ends with a full worked example.
15
UI typography: labels, buttons, truncation and user font sizes
Taught by Apple’s Human Interface Guidelines, with Material Design and Loren Brichter
Interface text is short, functional and unpredictable in length; design it to be scannable at small sizes, to wrap or truncate gracefully, and to grow when the user asks for bigger text.
Reading typography optimizes a paragraph you control. UI typography handles hundreds of tiny strings you don’t: a user’s name that might be “Li” or “Venkatanarasimharajuvaripeta”, a translated button label 40% longer than English, a price with seven digits, a user who has set their phone to the largest text size. The craft here is less about beauty and more about resilience.
Labels, buttons and captions
Labels sit close to what they label (proximity), in a quieter style than the value: smaller or muted, rarely both. Sentence case reads fastest.
Buttons use a verb, sentence or title case, and medium or semibold weight at body size or slightly smaller. Keep the label visually centred (mind the invisible line box from Chapter 10) and give it padding in em so it grows with text.
Captions and helper text are the smallest size in your scale, but not below 12px on the web (Apple’s smallest style is 11pt) and with enough contrast to read.
Numbers in UI are often the most important element on a screen (a balance, a count, a temperature). Let them be the largest text, in tabular figures, with units smaller and muted.
A card is a tiny type system. Five roles, two weights, two colours, three sizes.
Wrapping vs truncation
When text is longer than its space, you have three options: wrap it, truncate it, or let it overflow (never). The default should be wrap: it keeps all the information and adapts to translations and large text. Truncate only where a fixed height matters for scanning (list rows, tabs, table cells), and then:
Truncate at the end for titles and names (“Quarterly planning for the…”), using an ellipsis, and give the full text on hover, focus, or the detail view.
Truncate in the middle for file names and paths, where the end carries meaning (“Invoice_2026…final_v3.pdf”), as macOS Finder does.
Clamp multi-line previews (-webkit-line-clamp / line-clamp) to two or three lines, not one.
Never truncate numbers, prices, dates or anything a user must compare or act on.
Don't
Invoice_Acme_Studio_March_2026_final_v3.pdf
Invoice_Acme_Studio_March_2026_final_v2.pdf
End truncation on files. v2 and v3 look identical.
Do
Invoice_Acme…final_v3.pdf
Invoice_Acme…final_v2.pdf
Middle truncation. The distinguishing end survives.
Do
Quarterly planning for the new pricing experiment
Wraps to two lines; nothing hidden
Wrap by default. Let rows grow when the content is the point.
Dynamic Type and user font sizes
Many people enlarge text: on iOS through Dynamic Type (from the default “Large”, where Body is 17pt, up through accessibility sizes where Body reaches about 53pt), on Android with the font scale setting, on the web with browser zoom and default font size. WCAG requires that text can be resized to 200% without loss of content or function. Your layout must survive. That means: sizes in relative units (rem on the web, text styles on native), no fixed heights on text containers, buttons that grow, rows that wrap, and layouts that switch from horizontal to vertical when text gets big (iOS apps commonly stack label and value at accessibility sizes).
Lab: user text size
Fixed layout (heights in px, nowrap)
NotificationsDaily summary
Default currencyIndian rupee (₹)
BackupWeekly
Save changes
Flexible layout (rem, min-height, wrap)
NotificationsDaily summary
Default currencyIndian rupee (₹)
BackupWeekly
Save changes
Drag to 200%. The fixed layout clips labels and the button text; the flexible one grows rows and wraps values under labels. Real users run their phones at these sizes every day.
Minimum sizes
Practical floors: 16px for body text and form inputs on the web (iOS Safari zooms the page when focusing an input under 16px, which annoys users), 12–13px for secondary UI text, 11pt as Apple’s smallest system style. Below those, use them only for non-essential, decorative or legal-fine-print text, and even then, with sufficient contrast.
For the solo creator
Twice a month, set your phone to the largest accessibility text size and your browser to 200% zoom, and use your product for five minutes. You will find clipped buttons and overlapping labels within seconds. Fix them before users write in. It’s the cheapest usability test there is.
Do
Wrap by default; truncate deliberately with an escape.
Use relative units and text styles that scale with user settings.
Make inputs at least 16px on mobile web.
Don't
Fix heights on anything containing text.
Truncate numbers, prices or dates.
Set labels in px on native platforms that offer text styles.
In the wild
iOS SettingsApple
At accessibility text sizes, rows stack the label above the value and grow vertically rather than truncating. The layout itself changes shape as type grows.
macOS FinderApple
Truncates long file names in the middle, keeping the start and the extension visible. Truncate where the information isn’t.
TweetieLoren Brichter, 2008
Set tweet text, names and metadata with clear weight and colour steps in fast-scrolling rows, a pattern most timeline apps followed. Scannable rows come from consistent roles, not decoration.
Common mistakes
Designing only with short English strings
Mock data is “John Doe” and “Save”.
Test with long names, German or Tamil translations, seven-digit numbers and 200% text. Keep these as fixtures.
Truncation with no way to see the full text
The ellipsis fixed the layout, so the job felt done.
Provide a tooltip on hover/focus, an expanded detail view, or a wrap on tap.
15px inputs on mobile web
It matched the design’s label size.
Use 16px or more for input text, or users get an unexpected zoom on focus in iOS Safari.
Check yourself
In a document list, titles are often long and many share the same beginning (“Meeting notes – Monday”, “Meeting notes – Tuesday”). Rows must stay one line. What should you do?
When beginnings repeat, the distinguishing information is at the end. Middle truncation or a separate date column keeps rows distinct. Shrinking text hurts legibility and overflow breaks layout.
Exercise 15.1 45 minutes · on your own product
The stress fixtures
Create test data: a 40-character name, a 1-character name, a ₹12,34,56,789.00 amount, a translated label 40% longer, and an emoji in a title.
Load it into your three busiest screens.
Run them at 100%, 150% and 200% text size (or browser zoom).
Fix every clip, overlap and unwanted truncation; decide deliberately where to wrap or truncate.
You're done when: your three screens survive the fixtures at 200% with no clipped or overlapping text, and the fixtures are saved for future testing.
Beginner
Competent
Strong
Fixtures created; issues listed.
Issues fixed with wrapping, relative units and min-heights.
Layouts adapt structurally at large sizes (stacking), and fixtures are part of your regular test routine.
16
Rendering and loading
Taught by Matthew Carter (on screen fonts), with web performance practice
The same font looks different on macOS, Windows and Android, and it may arrive late or not at all; test on real platforms and load fonts so text is readable immediately and doesn’t jump when the font arrives.
Why your font looks different on Windows
Text rendering turns ideal outlines into pixels, and platforms make different trade-offs. macOS has long favoured fidelity to the outline shape, which looks smooth and slightly heavier and blurrier; since macOS Mojave (2018) it no longer uses subpixel antialiasing by default, so text on non-Retina Mac screens looks lighter than it used to. Windows, with ClearType and DirectWrite, has favoured snapping strokes to the pixel grid for sharpness, which relies more on hinting (instructions in the font that tell the rasterizer how to fit the grid). A font with poor hinting can look crisp on a Mac and ragged or thin on a Windows laptop. On high-density screens (2x and above) these differences shrink a lot; on the 1x office monitors many people still use, they matter.
Pixels are coarse. At body sizes a stem is one or two pixels wide; how the system rounds it changes the weight and sharpness of the whole paragraph.
A CSS note: -webkit-font-smoothing: antialiased only affects macOS browsers, making text look lighter. Many sites set it globally; it can help light text on dark backgrounds, but on a light background it often makes body text too thin. Use it deliberately, not by habit.
Font loading: FOIT, FOUT and layout shift
Web fonts download after the page starts rendering. Browsers then choose between two failure modes. FOIT (flash of invisible text): text is hidden until the font arrives, typically for up to about three seconds, and on a slow connection users stare at a blank page. FOUT (flash of unstyled text): text shows in a fallback font immediately and swaps when the web font loads, which may shift the layout. You control this with font-display in @font-face:
Value
Behaviour
Use it for
swap
Fallback immediately, swap whenever the font arrives
Body text, most cases
optional
Very short wait; if the font isn’t ready, use fallback for this page view
When stability matters more than the exact font; repeat visits get it from cache
fallback
Short invisible period, short swap window, then stick with fallback
A compromise
block
Invisible until loaded (up to a timeout)
Icon fonts only, where a fallback would show nonsense
Show text immediately, and make the swap invisible. Metric overrides on the fallback font make it occupy the same space as the web font.
A loading recipe
Self-host WOFF2 files from your own domain (fast, private, no third-party dependency).
Subset to the characters and scripts you need (with unicode-range so other scripts load only on demand), but keep the OpenType features you use.
Use one variable file instead of many static weights where you can.
Preload the one or two files needed above the fold: <link rel="preload" as="font" type="font/woff2" crossorigin>.
Set font-display: swap (or optional) and define a fallback @font-face that uses a local font with size-adjust, ascent-override and descent-override so its metrics match. Several frameworks (for example Next.js’s font tooling) generate these for you.
For the solo creator
The system font stack has zero loading cost, zero layout shift and zero licence risk. If you choose a web font, budget one afternoon to do the recipe properly once, put it in your project template, and never think about it again. Test with your browser’s network throttling set to “Slow 4G”.
Do
Test on a Windows machine and a 1x screen, not only on a Retina Mac.
Self-host, subset, preload and use swap or optional.
Match fallback metrics to avoid layout shift.
Don't
Hide text while fonts load.
Ship nine static weights “just in case”.
Set -webkit-font-smoothing: antialiased globally without checking light mode body text.
In the wild
Verdana & GeorgiaMatthew Carter and Tom Rickner, 1996
Drawn with the pixel grid in mind and extensively hand-hinted, they stayed crisp on low-resolution Windows screens for decades. Rendering is part of type design.
Google Fonts APIfont-display parameter
The CSS API accepts display=swap (as this page uses) and serves subsetted WOFF2 files split by unicode-range. Even if you self-host, copy its subsetting strategy.
Next.js next/fontVercel
Self-hosts fonts at build time and generates a size-adjusted fallback to reduce layout shift. Framework tooling can automate the hard part of loading.
Common mistakes
Only testing on a Retina Mac
It is the machine you own.
Borrow or buy a cheap Windows laptop or use a cloud browser testing service; check your smallest text and thin weights.
Layout jump on load
Fallback and web font have different widths and heights.
Choose a fallback with similar proportions and tune it with metric overrides; measure with Lighthouse’s CLS score.
Check yourself
Your landing page shows blank space for about 2 seconds on mobile networks, then text pops in. What change helps most?
Blank text is FOIT. Swap shows text immediately, preload shortens the wait, and a metric-matched fallback prevents the jump. Block causes the problem; more weights and third-party hosting add latency.
Exercise 16.1 60 minutes · on your own product
Loading and rendering check
Open your product with network throttling (Slow 4G) and cache disabled. Record what text does in the first three seconds.
List your font files, sizes and formats. Remove unused weights; convert to WOFF2; subset if appropriate.
Apply the five-step recipe.
Open your product on a Windows machine (or a cloud test) and screenshot body text, small labels and a thin weight.
You're done when: text appears immediately on a slow connection, total font weight is noted before and after, and you have Windows screenshots with any fixes made.
Beginner
Competent
Strong
font-display set.
Self-hosted, subset, preloaded; font bytes reduced.
No measurable layout shift from fonts, verified on Windows and a 1x screen.
17
Many scripts: Devanagari, mixed text and localization
Taught by Indian Type Foundry and Ek Type (Indic type design), with Google’s Noto project
Other scripts have different shapes, heights and rules; give them fonts designed for them, enough line height for their marks, and sizes matched by eye to your Latin text.
If your product might be used in India, Hindi, Marathi, Bengali, Tamil, Telugu and other Indian languages are not an edge case. Even an English-first app shows Indian names, addresses and user-generated text. The Latin rules in this guide don’t transfer automatically. Devanagari, used for Hindi, Marathi, Nepali and Sanskrit, is a good example of why.
How Devanagari differs
The headline (shirorekha). Most letters hang from a horizontal line at the top, which joins letters into words. Visually, the “x-height” is the body between the headline and the baseline.
Marks above and below. Vowel signs (matras) and other marks sit above the headline and below the baseline, and conjuncts stack. That needs more vertical room than Latin: line-height around 1.6–1.8 for body text, versus 1.4–1.6 for Latin.
Apparent size. At the same font-size, Devanagari often looks smaller than Latin because the main body is a smaller fraction of the em. It commonly needs a slightly larger size (often 10–15% more) to feel equal.
Shaping. Letters change form in combination (conjuncts, reordering of vowel signs). This requires proper OpenType shaping, which modern browsers and OSes do, but which breaks if you letter-space, fake bold or cut strings in the middle of a grapheme cluster.
No case. There are no capitals, so all-caps styling and tracking rules don’t apply; use weight and size for hierarchy.
More vertical territory. Marks above the headline and below the baseline make tight Latin line-heights collide in Devanagari.
Don't
आपका ऑर्डर भेज दिया गया है। डिलीवरी की स्थिति आप ऑर्डर पेज पर देख सकते हैं, और पते में कोई गलती हो तो हमसे संपर्क करें।
Latin settings applied. 15px at line-height 1.2: marks crowd the line above.
Do
आपका ऑर्डर भेज दिया गया है। डिलीवरी की स्थिति आप ऑर्डर पेज पर देख सकते हैं, और पते में कोई गलती हो तो हमसे संपर्क करें।
Script-specific settings. 17px, line-height 1.75, in a Devanagari font: calm and readable.
The Hindi sample reads: “Your order has been sent. You can see the delivery status on the order page, and contact us if there is a mistake in the address.”
Fonts for Indian scripts
Use a font designed for the script, not whatever the system falls back to. Good free options: the Noto families (Noto Sans Devanagari, Noto Serif Devanagari, and Noto for Bengali, Tamil, Telugu, Kannada, Malayalam, Gujarati, Gurmukhi and Odia), which aim at broad, consistent coverage; Hind and other families from Indian Type Foundry; Mukta from Ek Type; and IBM Plex Sans Devanagari, which matches IBM Plex Sans. Many of these were designed alongside a Latin companion, so the two scripts sit together well.
Mixed scripts on one screen
When a user’s Hindi name appears in an English UI, or an English brand name appears in Hindi text, two fonts share a line. Make it work by: listing a script-specific font in the stack (CSS picks per character, so font-family: Inter, "Noto Sans Devanagari", sans-serif uses Inter for Latin and Noto for Devanagari); setting lang attributes on content in other languages (this drives font selection, hyphenation and screen reader pronunciation); sizing so both scripts look the same size; and setting line-height for the taller script wherever it might appear.
Localization beyond Indian scripts
Expansion: translated strings are often 30% longer or more (German, Finnish); short English labels can double. Wrap, don’t clip (Chapter 15).
CJK: Chinese, Japanese and Korean text has no word spaces, wraps between most characters, needs larger fonts (fonts are big files; rely on system fonts or careful subsetting), and has its own punctuation rules. WCAG’s line-length guidance is 40 characters for CJK versus 80 for Latin.
Right-to-left: Arabic and Hebrew mirror layouts; use logical CSS properties (margin-inline-start, text-align: start) so your layout flips correctly.
Numerals and formatting: dates, numbers and currency vary by locale; always use locale-aware formatters.
For the solo creator
Even if you only ship English, add a Devanagari font to your fallback stack and set line-heights that won’t crush Indian names in user content. If you localize, start with one Indian language and test with a native reader; a single ten-minute session will teach you more than any rule.
Do
Use fonts designed for each script you support.
Give Devanagari and other Indic scripts more line height and slightly larger size.
Mark languages with lang and use logical CSS properties.
Don't
Letter-space or fake-bold complex scripts.
Truncate strings by character count (you may cut a cluster in half).
Assume Latin metrics and spacing work for every script.
In the wild
NotoGoogle
A project to cover all scripts in Unicode with harmonized designs, named for avoiding “tofu” (the empty boxes shown for missing glyphs). Coverage is a typographic responsibility.
Indian Type Foundry & Ek TypeIndia
Released many free, multi-script families (Hind, Mukta and others) through Google Fonts, designed by people who read the scripts daily. Prefer fonts made by native readers of the script.
Government and banking apps in IndiaUPI era
Many offer Hindi and regional-language interfaces, where tight Latin-style line-heights are a common source of clipped matras. Test vertical clipping in every script you ship.
Common mistakes
Clipped matras
Fixed-height containers or overflow: hidden with Latin line-heights cut off marks above and below.
Use script-aware line-heights and avoid clipping text containers vertically.
Missing glyphs (tofu)
The web font covers only Latin and there’s no fallback for other scripts.
Add script fonts to the stack and test with real names and content.
Check yourself
Your English app shows user names in list rows at 15px with line-height 1.25 and overflow hidden. Hindi names look cut off at the top. What is the best fix?
Matras need vertical room; clipping and tight line-height cut them. A proper font, more line height and no vertical clipping fix it. Reducing size hurts legibility; transliteration disrespects users; Devanagari has no case.
Exercise 17.1 40 minutes · on your own product
The script stress test
Insert Hindi (and if relevant Tamil or Bengali) names and a paragraph of Hindi into your product’s content (names, notes, titles).
Check: correct font, no tofu, no clipped marks, comparable apparent size, comfortable line-height.
Fix the font stack, line-heights and any clipping.
You're done when: mixed-script content renders correctly in your three main screens, with screenshots before and after.
Beginner
Competent
Strong
Issues found.
Font stack and line-heights fixed; no clipping.
Sizes matched by eye across scripts, lang attributes set, and a native reader confirmed it reads naturally.
18
Monospace, code and type in dark mode
Taught by Oliver Reichenstein, with Matthew Butterick
Code needs a monospace with unmistakable characters set slightly smaller than body text; dark mode needs slightly lighter weights and softer contrast, because light text on dark looks bolder and glows.
Choosing a code font
In code, every character carries meaning and readers scan vertically for alignment, so monospace (every glyph the same width) is the norm. What separates a good code font: distinct 0 O, 1 l I, and { } ( ) [ ]; punctuation big enough to see (a comma vs a full stop matters); a generous x-height; and enough weight to survive dark themes. Good choices include SF Mono and Menlo (Apple), Consolas and Cascadia Code (Microsoft), JetBrains Mono, IBM Plex Mono, Fira Code and Source Code Pro. For a web stack, ui-monospace, "SF Mono", Menlo, Consolas, monospace gives a good native mono on each platform, as this course uses.
Setting code
Size it down. Monospace looks bigger than proportional text at the same size because it is wider. Inline code usually sits at 0.85–0.9em of the surrounding text (this page uses 0.86em).
Leading 1.5–1.6 for code blocks; tight code is hard to scan.
Don’t wrap code by default in blocks; scroll horizontally, and keep lines short in examples you write.
Ligatures are a choice. Programming ligatures (Fira Code, JetBrains Mono, Cascadia Code) turn != or => into single symbols. Some developers love them; Butterick argued against them in an essay because they can misrepresent the actual characters. In a product that shows code to others, leave them off; in an editor, make them a setting.
Don't
const total = items.filter(i => i.qty > 0).reduce((s, i) => s + i.price * i.qty, 0); if (total != 0) { log("Total: " + total); }
Code in a proportional serif. No alignment, punctuation lost, wraps mid-expression.
Do
const total = items
.filter(i => i.qty > 0)
.reduce((s, i) => s + i.price * i.qty, 0);
if (total !== 0) log(`Total: ${total}`);
A real code font, slightly smaller, generous leading. Structure is visible; punctuation is clear.
Monospace for writing
iA Writer made a deliberate, debated choice: a monospace-derived face for prose writing. The argument is that monospace slows the eye slightly and makes the text feel like a draft, which encourages writing rather than admiring. iA later designed Duo (a few wide letters like m and w get extra width) and Quattro (closer to proportional) to keep that “draft” feel while reducing monospace’s gappy texture. The lesson for your product isn’t “use monospace”; it is that a font’s texture changes how people feel about the act they perform. Choose texture for the job.
Type in dark mode
Light text on a dark background looks heavier and slightly blurred than the same text dark-on-light. Part of this is perceptual (bright areas appear to spread into dark ones, an effect often called irradiation), part is rendering, and for people with astigmatism very bright text on black can appear to glow or smear (halation). Three adjustments help:
Soften the extremes. Avoid pure white (#FFF) on pure black (#000). Off-white on a very dark grey keeps contrast well above 4.5:1 while reducing glare.
Lighten weight slightly. If body text is 400 in light mode, it can look like 450 in dark mode. Variable fonts with a grade axis let you reduce apparent weight without changing width; otherwise consider one step lighter for large text, and check thin weights don’t disappear.
Re-check muted text. Secondary greys tuned for light mode often fail or look muddy in dark mode. Define them separately (this course defines every colour token twice).
Dark mode type: harsh vs tuned
Light mode
Regular weight, dark ink on white. The reference look your design started with.
Dark, untuned
Pure white on pure black, weights bumped “for punch”. Strokes bloom and the paragraph glows.
Light mode
Regular weight, dark ink on white. The reference look your design started with.
Dark, tuned
Off-white on near-black, regular weight, headings one step lighter. It now matches the light version’s apparent weight.
Without: maximum contrast and heavier weights make dark mode text look bolder and harsher than the light design.
With: softer contrast (still well above 4.5:1) and lighter weights make dark and light modes feel like the same typography.
Key idea
Dark mode isn’t inverted light mode. Type needs its own, slightly gentler settings.
For the solo creator
Make text colour and, if your font allows, weight or grade into tokens that switch with the theme. Then read one long screen in both modes, at night, at low screen brightness. Whichever mode feels heavier gets adjusted. Ten minutes, once.
Do
Use a code font with distinct 0/O and 1/l/I, at about 0.875em.
Soften dark mode contrast and lighten weights slightly.
Define secondary text colours separately per theme.
Don't
Set prose in monospace without a reason tied to the product’s job.
Use #FFF on #000 for long text.
Use thin weights in dark mode small text.
In the wild
iA WriterMono, Duo, Quattro
Offers three related faces so writers can choose how “draft-like” the text feels, and publishes them under an open licence. Texture is a product decision.
JetBrains MonoJetBrains, 2020
A code font with a tall x-height and distinct glyphs, designed for long reading sessions in an IDE, with optional ligatures. Code fonts are reading fonts for a specific kind of text.
Apple’s dark modemacOS Mojave, iOS 13
Uses near-black and dark grey backgrounds with off-white and grey label colours, rather than pure white on pure black. Even the platform tones down contrast for comfort.
Common mistakes
Code at body size
Inline code inherits 1em and looks oversized and heavy.
Set code to about 0.85–0.9em and check line spacing isn’t pushed apart by it.
Inverted colours only
Dark mode was created by swapping black and white.
Tune text colours, weights and secondary greys separately for dark.
Check yourself
Users of your reading app say dark mode is “tiring” after 20 minutes. Text is #FFFFFF, weight 500, on #000000. What do you try first?
Maximum contrast and heavier weight cause glare and bloom on dark backgrounds. Softer contrast and lighter weight usually fix the fatigue; the other options make it worse or are unrelated.
Exercise 18.1 30 minutes · on your own product
Two-theme type pass
Screenshot one long screen in light and dark mode side by side.
Squint: which looks heavier? Adjust dark text colour and weight until both feel the same.
If your product shows code or IDs, check the font distinguishes 0/O and 1/l/I, and size inline code to about 0.875em.
You're done when: light and dark screenshots look like the same typography, with contrast ratios noted (both at or above 4.5:1 for body).
Beginner
Competent
Strong
Dark colours softened.
Weights and secondary colours tuned per theme; code font checked.
Theme-aware tokens for colour and weight/grade, verified at night on a phone at low brightness.
19
Worked example: a plain article, refined in six steps
Putting it all together, with everything from Chapters 7 to 14
Good typography is a sequence of small, ordered decisions; applied in the right order, six steps turn default text into a calm, professional page.
Below is a short article as it might appear in a product changelog or blog, first with browser-ish defaults and no decisions. Step through it. Each step applies one chapter and changes only what that chapter controls. Notice that the biggest improvements come early (size, leading, measure) and the later ones are refinements. That ordering is the practical lesson: when time is short, do steps 1 and 2 first.
The order matters. Fix what every line depends on before polishing what a few lines show.
Lab: refine the article step by step
Engineering notes
How we cut our app's load time in half without a rewrite
Rohit Sharma · 12 March 2026 · 6 min read · 1,204 views1,204 views
For months our dashboard took 4-5 seconds4–5 seconds to show anything useful. Users called it "slow but fine"“slow but fine”, which is another way of saying they were quietly looking for alternatives.
We assumed we needed a rewrite. Instead, we measured. Three things turned out to matter: fonts that blocked rendering, a chart library loaded on every page, and an API call that waited for another one for no reason.
Start with what users see first
The fastest fix was the fonts. We had nine weights loading from a third-party server with font-display: blockfont-display: block, so text stayed invisible for up to three seconds on slow networks. We cut it to one variable file, self-hosted, with a matched fallback...… and the page started showing text almost immediately.
Step 0 · Plain: Arial 13px, line-height 1.2, full width, headings barely bigger, straight quotes. Nothing is wrong enough to be noticed; everything is slightly tiring.
What each step did, and why in this order
Body (Chapter 7). A screen serif at 18px, line-height 1.6, paragraph spacing instead of nothing. Every line in the article improved at once.
Measure (Chapter 7). The body column capped at about 34em, roughly 65–75 characters on desktop. Return sweeps became reliable.
Scale (Chapter 8). Title and subheading set from a scale, in the sans, with tighter leading and slight negative tracking on the title.
Rhythm (Chapter 10). More space above the subheading than below; title separated from the body. Sections now group visually.
Hierarchy (Chapter 9). The kicker became a tracked overline; metadata became smaller, muted sans. The title is now unambiguously first.
Details (Chapters 11–13). Curly quotes and apostrophe, an en dash for the range, a real ellipsis, balanced headings, pretty paragraph wrapping and tabular figures in the metadata.
Before
Before. A wall of grey; no entry point.
After
After. Title first, metadata quiet, body comfortable, sections grouped.
Checklist: type audit for your product
Choice
Setting
Details
Robustness
For the solo creator
Run this exact six-step sequence on one real screen of your product per week. The first time takes an hour; by the third time it takes fifteen minutes, because steps 1–3 become tokens you reuse, and only 4–6 need judgement per screen.
Do
Fix body size, leading and measure before anything else.
Change one thing per step and look again.
Keep a before screenshot; the difference motivates.
Don't
Start with the font or the details.
Change five settings at once and lose track of what helped.
Stop at step 2 for headings-heavy screens; hierarchy matters there.
In the wild
Reader modesSafari, Firefox, Edge
Apply roughly steps 1–4 automatically to any page: a readable size, generous leading, a narrow column, and clean spacing. The first four steps are so valuable browsers ship them as a feature.
Ghost & SubstackPublishing platforms
Default article templates already have a comfortable body size, measure and heading scale, which is a large part of why writers choose them. Good defaults are a product advantage.
MediumEarly 2010s
Built its reputation partly on how good plain text looked by default: large serif body, narrow column, calm metadata. Typography can be the product’s first impression.
Common mistakes
Polishing details on a broken base
Curly quotes and balanced headings are satisfying, quick wins.
Do them, but only after body size, leading and measure are right.
Refining one page, not the system
The article looks great; the settings live in that page’s CSS.
Promote every decision to tokens so the next page starts at step 6.
Check yourself
You have 20 minutes before launch and your blog template is untouched defaults. Which two steps do you do?
Body and measure affect every line a reader sees and take minutes. The rest are valuable but lower impact per minute.
Exercise 19.1 90 minutes · on your own product
Six steps on your longest screen
Pick the screen with the most text in your product. Screenshot it as step 0.
Apply steps 1 to 6 in order, screenshotting after each.
Arrange the seven screenshots in a row and write one sentence under each about what changed and how it felt.
Promote every setting you changed into a token or text style.
You're done when: you have a seven-frame strip and the settings live in your design tokens, not the screen.
Beginner
Competent
Strong
Steps applied with some skipped.
All six applied in order, with notes.
Tokens updated and the improvement carried to at least two other screens with no extra per-screen work.
Wrap-up
Ten things to remember
Type is most of your interface; type settings are the highest-leverage, most global design decisions you make.
X-height, aperture, contrast and spacing predict how a face behaves on screens. Judge faces by these, not by their specimen.
Legibility is the face; readability is the setting. Most problems are settings, and settings are free to fix.
Start with the system font; leave it only for a reason you can name. One family is usually enough.
Body 16–20px, line-height 1.4–1.6, 45–75 characters per line, tuned together.
Five to seven named sizes from a gentle scale; weight, colour and space for the minor levels.
More space above headings than below; spacing from tokens on one base unit.
Ragged right by default; balance headings; justify only with hyphenation and width.
Curly quotes, real dashes and ellipses in prose; tabular figures for data; tracked caps; straight characters in code.
Make type robust: user text sizes, long strings, Windows rendering, slow fonts, Indian scripts and dark mode.
Self-assessment: I can…
Practice assignment for the next two weeks
Typography improves with daily looking and weekly doing. Spend about 20 minutes a day.
Days 1–3: See. Each day, screenshot one screen from an app you admire and one you don’t. Annotate size, leading, measure, scale steps, weights and one detail (quotes, figures, tracking). Use this guide’s vocabulary.
Days 4–5: Decide. Write your type decision record (Exercise 5.1) and set body tokens (Exercise 7.1).
Days 6–8: Systematize. Collapse your sizes into a named scale (8.1), fix spacing (10.1) and hierarchy (9.1).
Days 9–10: Detail. Punctuation sweep (12.1), number audit (13.1), tracking tokens (14.1).
Days 11–13: Harden. Stress fixtures at 200% (15.1), loading and Windows check (16.1), script test (17.1), dark mode pass (18.1).
Day 14: Show. Run the six-step worked example on your longest screen (19.1), complete the type audit checklist, and put a before/after strip somewhere you’ll see it.
Reading list
The Elements of Typographic Style
Robert Bringhurst (1992, later editions) · The classic on text typography: measure, rhythm, scale, details. Print-oriented but the principles transfer.
Butterick’s Practical Typography
Matthew Butterick (free online) · Blunt, practical rules with numbers; the fastest way to fix everyday text. Read the summary page first.
Stop Stealing Sheep & Find Out How Type Works
Erik Spiekermann and E. M. Ginger · A friendly, visual introduction to seeing and choosing type.
Thinking with Type
Ellen Lupton · Letter, text, grid, with many visual examples; good for building vocabulary.
On Web Typography
Jason Santa Maria (A Book Apart, 2014) · Choosing and pairing type for screens, with a designer’s eye.
Web Typography
Richard Rutter (2017) · Detailed, technical guide to setting type with CSS, from measure to OpenType features.
“Web Design is 95% Typography”
Oliver Reichenstein, Information Architects (2006) · The short essay that frames this whole guide.
“The Crystal Goblet”
Beatrice Warde (1930 lecture) · Why type in the service of reading should be invisible.
“The Science of Word Recognition”
Kevin Larson, Microsoft (2004) · The readable research review behind Chapter 4’s word-shape discussion.
“More Meaningful Typography”
Tim Brown, A List Apart (2011) · The article that brought modular scales to web design.
Typeface Mechanics series
Tobias Frere-Jones (essays on his studio’s site) · How type designers solve overshoot, spacing and other optical problems.
Apple Human Interface Guidelines: Typography, and Material Design 3: Typography
Apple; Google · The platform rules for text styles, sizes and dynamic type you’ll build against.
Next, Reading & Writing applies everything here to calm tools for long-form reading and focused writing, and Accessible & Inclusive goes deeper on contrast and text scaling.