optical-margin
Hang it right.
Every font.
CSS hanging-punctuationis Safari-only and has no weight control. Optical Margin measures each punctuation character's actual hang amount from Canvas font metrics and applies it as a margin. Works in every browser, with every font.
Live demo — toggle the hangs
"Typography is the craft of endowing human language with a durable visual form," wrote Robert Bringhurst, — and that form begins at the margin. When a line opens with a quotation mark, the mark should hang in the margin so the first letter of the word aligns with the lines above and below it. When a line ends with a comma, the comma should similarly hang so the last letter — not the punctuation — forms the right edge. CSS hanging-punctuation does this in Safari only. Optical Margin does it everywhere, for every font, by measuring the actual hang amount from Canvas font data rather than guessing from a lookup table.
Punctuation hangs at both margins.
Why not CSS?
hanging-punctuation is incomplete
The CSS property is Safari-only. It doesn't let you control hang amount, threshold, or which characters hang. And it uses hard-coded character tables, not the actual font metrics — so a T in one font hangs the same amount as a T in another.
Font-metric measurement
Canvas measureText returns both advance width and visual bounds. The difference is the optical hang amount — how far the character could move into the margin before it would look misaligned. This gives accurate results for every font without a lookup table.
Usage
Drop-in component
import { OpticalMarginText } from '@liiift-studio/optical-margin'
<OpticalMarginText hangStart={true} hangEnd={true}>
"Your paragraph text here..."
</OpticalMarginText>Options
| Option | Default | Description |
|---|---|---|
| hangStart | true | Hang opening punctuation at line starts. |
| hangEnd | true | Hang closing punctuation and sentence-end marks at line ends. |
| threshold | 0.5 | Minimum hang amount in px before applying. |
| maxHangRatio | 0.9 | Max proportion of advance width to hang (0–1). |