Reading the metrics
Last updated 2026-11-02
- 度量
- metrics
- unitsPerEm
- 基线
- ascender
- descender
- viewBox
- em 方框
- 百分比
On this page
The inspector's metrics panel draws one glyph inside one em square, plus the boundaries the font declares. It is not a judgement of the typeface; it is a working drawing for how much room a line needs.
Coordinates first: font units, up is negative
- Every number is in font units (fractions of
unitsPerEm), never pixels; - the baseline is y = 0;
- up is negative (the SVG convention).
So an ascender of 800 font units is drawn at y = -800. On screen it sits above; as a value it is positive. Two ways of saying the same thing.
Because pixels never enter, the drawing is size-independent: identical at 12px and 120px. Scaling is entirely the SVG viewBox.
The nine layers
| Layer | Draws | Source |
|---|---|---|
| Baseline | The baseline (y = 0) | — |
| hhea | Typographic ascent and descent | hhea.ascender / descender |
| OS/2 typo | The typesetting set | OS/2.sTypoAscender / sTypoDescender |
| OS/2 win | Windows clipping bounds | OS/2.usWinAscent / usWinDescent |
| Cap height | Uppercase height | OS/2.sCapHeight |
| x-height | Lowercase x height | OS/2.sxHeight |
| Underline | Underline position | post.underlinePosition |
| Advance / side bearings | The vertical lines | the glyph's advanceWidth and leftSideBearing |
| Glyph bounding box | What the glyph actually occupies (ink) | glyph bounding box |
Layers can be switched off individually — that only declutters the drawing; the table keeps every row.
unitsPerEm = 1000. On the right are raw field values (watch the signs — descender and underline are negative); along the bottom are the three horizontal references. The grey box is the glyph's ink, which is not the same thing as advance: the difference is the right side bearing.
The vertical lines
- Origin (x = 0): where the glyph starts;
- advance: the horizontal distance it takes; the next glyph starts here;
- lsb (left side bearing): from the origin to the ink;
- 1 em: the line at x =
unitsPerEm, for comparing how much of an em the glyph uses.
Right side bearing has no line but does have a row: advance − lsb − ink width.
The table
Every row gives font units and percentage of one em (value ÷ unitsPerEm). Percentages compare across fonts; absolute numbers do not, because unitsPerEm may be 1000 or 2048.
Rows include:
- baseline plus the three extent sets (hhea / typo / win) and their line gaps;
- cap height, x-height;
- underline position and thickness;
unitsPerEm;- the glyph's advance, lsb, rsb;
- the ink box's left, right, top, bottom and height.
Three sign conventions
| Value | Typical | Meaning |
|---|---|---|
hhea.descender |
negative | how far below the baseline |
OS/2.usWinDescent |
positive | "how far down", not a coordinate |
post.underlinePosition |
negative | underline top below the baseline |
post.italicAngle |
negative | leaning right |
This site normalises all of it into "up is negative" inside shared/src/fonts/metrics.ts; components never flip again. The drawing is consistent, the table shows raw values — a positive number in the table does not mean the drawing is wrong.
Two y directions
The most error-prone part of the implementation, and the first suspect when a drawing looks flipped:
- glyph outlines (SVG path) are SVG-oriented: y increases downwards;
- bounding boxes and metrics are font-oriented: y increases upwards.
Boxes need their top and bottom swapped, or the whole box flips. Collecting that conversion in one file is exactly how this site avoids "one line quietly mirrored".
Why some characters cannot be drawn
If the glyph index is 0 (.notdef, the tofu box), the font does not have this character. The metrics shown are .notdef's, meaning nothing about any real glyph — so the panel says "this font has no such character" instead of drawing a meaningless diagram.
Further reading
shared/src/fonts/metrics.ts(the model and its comments)- OpenType spec:
hhea,OS/2,post - This site: head / hhea / post