Font Converter

Font Metrics: Understanding Vertical Measurements

Learn how font metrics in OS/2 and hhea tables control line height, text alignment, and cross-platform rendering consistency.

Key Takeaways

  • • OS/2 and hhea tables both contain vertical metrics (often different values)
  • • Windows and Mac may use different metric sources for line height
  • • Metrics are preserved during format conversion
  • • CSS metric overrides can match fallback fonts to custom fonts

Font metrics define the vertical measurements that control line height, baseline positioning, and text alignment. These values are stored primarily in two tables: OS/2 and hhea. Unfortunately, these tables often contain different values, and different operating systems may choose different sources, causing cross-platform rendering inconsistencies.

All metric values in OpenType fonts are expressed in font units—fractions of the UPM (units per em). The UPM is defined in the head table and is typically 1000 units for CFF fonts and 2048 units for TrueType fonts. A sTypoAscender of 800 in a 1000-UPM font means the ascender reaches 80% of the way up from the baseline to the top of the em square. This unit system makes fonts resolution-independent: the same values produce correct spacing whether the font renders at 12px or 120px.

OS/2 Table Metrics

FieldDescriptionTypical Value
sTypoAscenderTypographic ascender (recommended)800-1000
sTypoDescenderTypographic descender (negative)-200 to -300
sTypoLineGapExtra space between lines0-200
usWinAscentWindows clipping ascent900-1200
usWinDescentWindows clipping descent (positive)200-400
sxHeightHeight of lowercase x450-550
sCapHeightHeight of capital letters650-750

USE_TYPO_METRICS Bit

The OS/2 table contains a critical flag called fsSelection bit 7, known as USE_TYPO_METRICS (value 0x0080). When this bit is set, Windows renders line height using the typographic metrics (sTypoAscender + sTypoDescender + sTypoLineGap) instead of the Windows-specific values (usWinAscent + usWinDescent). Setting this bit is the recommended approach for new fonts because it produces consistent line heights across Windows and macOS.

USE_TYPO_METRICS not set

Windows uses usWinAscent/usWinDescent for line height. macOS uses hhea ascender/descender. These often differ, causing layout inconsistency.

USE_TYPO_METRICS set (recommended)

Both Windows and macOS use sTypo* values. Line height becomes predictable across platforms. All modern Google Fonts set this bit.

Cross-Platform Rendering Differences

Without USE_TYPO_METRICS, the same font can render with different line heights on different operating systems. Here is a real-world example using a hypothetical font with 1000 UPM:

Metric SourceWindows (legacy)macOS / USE_TYPOLine Height at 16px
usWinAscent=1050, usWinDescent=3501400 units22.4px
sTypoAscender=800, sTypoDescender=−200, sTypoLineGap=01000 units16px (1.0 line-height)

Without USE_TYPO_METRICS, this font renders 40% taller on Windows than macOS—a common cause of layout bugs in multi-platform web projects.

The UPM value—whether 1000 or 2048—is a historical artifact with practical consequences. CFF fonts inherited 1000 from the PostScript Type 1 specification, where fonts were designed on a 1000-unit grid that could be scaled arbitrarily. TrueType fonts adopted 2048 because higher coordinate resolution gives more granularity for hinting instructions: TrueType's bytecode hinting operates in integer font units, so a 2048-UPM font allows finer positioning of hint control values than a 1000-UPM equivalent. Changing UPM requires scaling every metric value, every glyph coordinate, and every table reference proportionally—it is not a simple header field change. Conversions that silently change UPM can introduce systematic rounding errors across the entire glyph set.

Diagnosing cross-platform line height inconsistencies is one of the most common font metrics challenges for web developers. The reliable test is to apply line-height: 1 on an element and compare its computed height in pixels across Chrome on Windows and Chrome on macOS. A font without USE_TYPO_METRICS set will produce different computed heights because Windows and macOS query different metric sources when calculating line boxes. After setting USE_TYPO_METRICS and verifying that OS/2 sTypo values and hhea values agree, the computed height should be identical across platforms. The fonttools CLI command fonttools inspect -t OS/2 font.ttf shows all relevant fields, and the --layout-features flag on pyftsubset preserves these values during subsetting.

hhea Table Metrics

The hhea (horizontal header) table contains Mac-style vertical metrics:

ascender

Distance from baseline to top of tallest glyph

descender

Distance from baseline to bottom of lowest glyph (negative)

lineGap

Extra spacing between lines

Cross-Platform Issue

macOS uses hhea metrics for line height. Windows traditionally uses usWinAscent/usWinDescent. If these values differ significantly, your text will have different line spacing on each platform. Modern browsers increasingly use sTypo* values when the USE_TYPO_METRICS bit is set in OS/2.

Recommended Metric Configuration

For new fonts targeting web and cross-platform desktop use, the industry consensus is:

sTypoAscender + sTypoDescender + sTypoLineGap = UPM value. This produces line-height: 1.0 behavior with no extra spacing.

usWinAscent = maximum glyph ascent, usWinDescent = maximum glyph descent. These define the clipping box on Windows—values too small clip descenders.

Set USE_TYPO_METRICS (fsSelection bit 7). This tells Windows to use sTypo* values, eliminating the dual-metric inconsistency.

hhea ascender/descender = sTypoAscender/sTypoDescender. Keep hhea metrics consistent with OS/2 typographic metrics to avoid macOS inconsistencies.

The hhea table's ascender and descender fields were originally designed for macOS's QuickDraw rendering system and carried different design philosophy than the OS/2 sTypo fields. Early font designers often set hhea values to the actual maximum glyph extent—the tallest ascender and deepest descender found anywhere in the character set—rather than the typographic design values that define the intended rhythm. This made hhea-based line height significantly larger than the designer's intent, because occasional extreme glyphs (accented capitals reaching unusually high, below-baseline swash letters) inflated the spacing for every line of text. Modern practice aligns hhea ascender and descender with sTypo equivalents and uses USE_TYPO_METRICS to ensure Windows also applies the intended values.

Excessive line height caused by inflated hhea values is often misdiagnosed as a CSS problem when it is actually a font metrics problem. A font with hhea.ascender of 1200 and hhea.descender of −400 in a 1000-UPM font produces a line box of (1200 + 400) ÷ 1000 = 1.6 line heights at any font size—significantly more spacing than the 1.2 that most UI design assumes. Setting line-height: 1 in CSS does not fix this because hhea metrics determine the natural line box size that is then scaled by the CSS line-height multiplier. Correcting the hhea values in the font itself is the only way to restore normal spacing behavior across all rendering contexts.

CSS Metric Overrides

CSS provides descriptors to override font metrics, primarily useful for matching fallback fonts to custom fonts to prevent layout shift:

@font-face {
  font-family: 'CustomFont-Fallback';
  src: local('Arial');
  /* Match Arial metrics to your custom font */
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
  size-adjust: 105%;
}

body {
  font-family: 'CustomFont', 'CustomFont-Fallback', sans-serif;
}

To calculate the correct percentage values for ascent-override and descent-override, divide the font's metric values by the UPM, then multiply by 100. For a font with UPM 2048, sTypoAscender 1900, and sTypoDescender −480: ascent-override: 92.77% (1900÷2048×100) and descent-override: 23.44% (480÷2048×100). The size-adjust property compensates for overall glyph size differences between the custom font and the fallback.

CLS Prevention

Metric overrides are a key technique for eliminating Cumulative Layout Shift (CLS) caused by font swapping. When a fallback font has different metrics than the custom web font, text reflows as the web font loads. By defining a specially-tuned fallback with matching metrics, text occupies the same space before and after the font loads—CLS score stays at zero. Tools like fontaine (npm) automate calculating these values from font files.

Convert with Metrics Preserved

Our converter maintains all metric tables during format conversion.

Try Font Converter
Sarah Mitchell

Written by

Sarah Mitchell

Product Designer, Font Specialist

Marcus Rodriguez

Verified by

Marcus Rodriguez

Lead Developer

Font Metrics FAQs

Common questions about OS/2, hhea, and vertical metrics