Font Weight Classification & Stem Thickness
Every font family ships with names like Light, Regular, Bold, and Black, plus a number underneath (300, 400, 700) that software actually reads. Neither the name nor the number is arbitrary: both trace back to a single physical measurement, the thickness of a stroke relative to the height of the capital letters. This article covers how that measurement is taken, the standardized scale it maps to, and includes a live tool so you can watch a stroke get heavier and see exactly where the classification changes.
Font weight measurement, in one screen
A font's named weight and its numeric usWeightClass both derive from the same underlying measurement: how thick a stroke is relative to the letter's height.
"Bold" is a design decision, not a measurement. A type designer draws a heavier version of a typeface by eye, the same way side bearings and kerning get set by eye elsewhere in this series. But once that heavier design ships as a font file, software has to do a few things a human reader never needs to: sort a family's styles from lightest to heaviest, pick the closest match when a document asks for bold text but the font doesn't ship one, and let a variable font interpolate smoothly between a Thin master and a Black master (see the Variable Fonts article). None of that works from a name alone: "Semibold" in one family and "Medium" in another can be visually identical, or wildly different weights, because there's no enforced meaning behind either word on its own.
So the industry settled on a number instead of an adjective: usWeightClass, a field in every OpenType font's OS/2 table, holding a value from 1 to 1000. In practice, fonts cluster around ten standard steps (100, 200, 300, up through 900, plus 950 for the very heaviest cuts), and CSS's font-weight property uses this exact same scale, which is why font-weight: 700 reliably means Bold across essentially every font on the web.
Before any of this was standardized, every type foundry named its weights however it liked, and the vocabulary never quite lined up between them. "Roman" and "Book" both typically meant the plain text weight. The choice between them was really just house style, carried over from metal-type specimen books. "Demi" (short for demi-bold) was the common name for a moderately heavy weight for most of the 20th century; "Semibold" only became the standard term once digital type settled around it. At the heavy end, "Black," "Ultra," "Fat," and "Poster" have all been used by different foundries for essentially the same category, with no agreed line marking where one ends and the next begins.
That looseness was fine as long as a person was reading a specimen sheet and making a judgment call. It stopped being fine once software needed to sort, substitute, and interpolate between weights automatically. A font picker can't reason about whether one foundry's "Medium" is heavier than another's "Semibold" without a shared scale underneath the names. PANOSE-1 formalized that scale first, in the early days of desktop publishing, specifically so an operating system could find a reasonable substitute when the exact font requested wasn't installed. OpenType's OS/2.usWeightClass field followed the same order at finer resolution, and it's what every modern font actually carries. The friendly name on a font menu, whatever a particular foundry chose to call it, is just a label mapped onto one of these numbers underneath.
The number itself isn't arbitrary. It's backed by a physical measurement defined by the PANOSE-1 classification system: the thickness of a stroke, measured as a percentage of the capital letters' height. That measurement rests on two simple, stable reference letters rather than the whole alphabet. Caps height (labeled a) is the simpler of the two: measure along the midline of the H's left stem, from the baseline up to the cap line. Stem thickness (labeled c) takes a little more care, because a capital E has three horizontal strokes, and no single vertical measurement means the same thing at every height on the letter. The convention is to draw a horizontal line exactly halfway between the upper and lower arms, equidistant from each and marked b and b in the diagram, and measure the width of the vertical stem along that one line. Divide c by a, and the result is stem thickness as a percentage of caps height: the number the entire classification table is built from.
Reading down the table follows the same logic as the live demo above: each row's range runs from the previous row's ceiling (exclusive) up to its own ceiling (inclusive), so a font's stem-to-caps-height ratio falls into exactly one row, with no gap or overlap between classes.
| PANOSE | PANOSE name | usWeightClass | OpenType name | Stem thickness (% of caps height) | Stem thickness (units, caps height = 700) |
|---|---|---|---|---|---|
| 2 | very light | 100 | Thin | ≤ 5% | ≤ 20 |
| 3 | light | 200 | Extra-light | > 5% to ≤ 5.6% | > 20 to ≤ 39 |
| 4 | thin | 300 | Light | > 5.6% to ≤ 10% | > 39 to ≤ 70 |
| 5 | book | 400 | Regular | > 10% to ≤ 13.3% | > 70 to ≤ 93 |
| 6 | medium | 500 | Medium | > 13.3% to ≤ 18.1% | > 93 to ≤ 127 |
| 7 | demi | 600 | Semi-bold | > 18.1% to ≤ 22.3% | > 127 to ≤ 156 |
| 8 | bold | 700 | Bold | > 22.3% to ≤ 28.6% | > 156 to ≤ 200 |
| 9 | heavy | 800 | Extra-bold | > 28.6% to ≤ 40% | > 200 to ≤ 280 |
| 10 | black | 900 | Black | > 40% to ≤ 50% | > 280 to ≤ 350 |
| 11 | extra black | 950 | Extra-black | > 50% | > 350 |
Now put the table to work. Drag the slider, which snaps to the ten standard usWeightClass steps but can also stop anywhere between them, and watch the classification, the range, and the letterform all update together.
Stem thickness: > 10% to ≤ 13.3% of caps height
If caps height = 700: > 70 to ≤ 93 units (displayed at 82 units)
Every typeface is drawn on its own grid, a units-per-em setting the designer chooses, commonly 1000 or 2048, so a raw stem width in font units means nothing on its own; 70 units is chunky on a 1000-unit grid and barely visible on a 2048-unit one. Measuring stem thickness as a percentage of caps height cancels that out: both numbers come from the same font, drawn on the same grid, so the ratio between them stays meaningful no matter how fine or coarse that grid is, and no matter what point size the text is eventually set at. It's the same reason em-based units show up throughout font engineering: a ratio travels; an absolute measurement doesn't.
This is also why the scale lines up so neatly with usWeightClass. OpenType requires that 400 mean Regular for any font that uses the scale at all (the same rule the wght axis inherits in variable fonts), and Regular's ceiling in the table above, 13.3%, sits right in the middle of the practical range a text face can use without looking either fragile or heavy-handed at body-copy sizes.