Typography
Typography rendering details that make interfaces feel better.
Text Wrapping
text-wrap: balance
Distributes text evenly across lines, preventing orphaned words on headings and short text blocks. Only works on blocks of 6 lines or fewer (Chromium) or 10 lines or fewer (Firefox) — the balancing algorithm is computationally expensive, so browsers limit it to short text.
/* Good — even line lengths on short text */
h1, h2, h3 {
text-wrap: balance;
}/* Bad — default wrapping leaves orphans */
h1 {
/* no text-wrap rule → "Read our
blog" instead of balanced lines */
}/* Bad — balance on long paragraphs (silently ignored, wastes intent) */
.article-body p {
text-wrap: balance;
}Tailwind: text-balance
text-wrap: pretty
Prevents orphaned words (a single word dangling on the last line) by adjusting line breaks throughout the paragraph. Unlike balance, it doesn't try to equalize line lengths — it just ensures the last line isn't embarrassingly short. Works on text of any length with no line-count limit.
This should be your default for short-to-medium text — paragraphs, descriptions, captions, list items, card text. For very long text (10+ lines), skip both pretty and balance — the browser's default wrapping is fine and you avoid unnecessary layout cost.
/* Good — descriptions, captions, short paragraphs */
p, li, figcaption, blockquote {
text-wrap: pretty;
}// Tailwind
<p className="text-pretty">
A short paragraph that won't leave an orphan on the last line.
</p>Tailwind: text-pretty
When to Use Which
| Scenario | Use |
|---|---|
| Headings, titles where even distribution matters | text-wrap: balance |
| Short-to-medium text — paragraphs, descriptions, captions, UI text | text-wrap: pretty |
| Long text (10+ lines), code blocks, pre-formatted text | Neither — leave default |
Font Smoothing (macOS)
On macOS, text renders heavier than intended by default. Apply antialiased smoothing to the root layout so all text renders crisper and thinner.
/* CSS */
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}// Tailwind — apply to root layout
<html className="antialiased">Good vs. Bad
/* Good — applied once at the root */
html {
-webkit-font-smoothing: antialiased;
}
/* Bad — applied per-element, inconsistent */
.heading {
-webkit-font-smoothing: antialiased;
}
.body {
/* no smoothing → heavier than heading */
}Note: This only affects macOS rendering. Other platforms ignore these properties, so it's safe to apply universally.
Tabular Numbers
When numbers update dynamically (counters, prices, timers, table columns), use tabular-nums to make all digits equal width. This prevents layout shift as values change.
/* CSS */
.counter {
font-variant-numeric: tabular-nums;
}// Tailwind
<span className="tabular-nums">{count}</span>When to Use
| Use tabular-nums | Don't use tabular-nums |
|---|---|
| Counters and timers | Static display numbers |
| Prices that update | Decorative large numbers |
| Table columns with numbers | Phone numbers, zip codes |
| Animated number transitions | Version numbers (v2.1.0) |
| Scoreboards, dashboards |
Caveat
Some fonts (like Inter) change the visual appearance of numerals with this property — specifically, the digit 1 becomes wider and centered. This is expected behavior and usually desirable for alignment, but verify it looks right in your specific font.
/* With Inter font:
Default: 1234 → proportional, "1" is narrow
Tabular: 1234 → all digits equal width, "1" centered */