OpenType Features You Should Be Using
Ligatures, small caps, oldstyle figures, tabular figures, stylistic sets — the full CSS font-feature-settings and font-variant-* cookbook with real code examples.
OpenType Features You Should Be Using
The Hidden Layer of Professional Type
Most designers use typefaces at their defaults. The defaults are adequate — they produce correct, readable text. But most professional typefaces ship with a layer of additional glyphs and behaviors — OpenType features — that refine and enhance the type in ways that separate workmanlike typography from genuinely excellent typography.
OpenType features are accessed through CSS. Some are enabled by default; most require explicit activation. This article is a practical guide to the features that matter most, with copy-paste CSS for each.
The Two CSS Approaches
There are two ways to enable OpenType features in CSS:
font-variant-* properties (the modern approach): individual, semantic properties for each feature class. Readable, maintainable, and supports inheritance correctly.
font-feature-settings (the low-level approach): a string of four-letter OpenType feature codes. More flexible, required for features not covered by font-variant-*, but harder to maintain.
/* Equivalent statements: */
/* Modern font-variant approach */
body {
font-variant-ligatures: common-ligatures;
font-variant-numeric: oldstyle-nums;
}
/* Low-level font-feature-settings */
body {
font-feature-settings: "liga" 1, "onum" 1;
}
Use font-variant-* when available; fall back to font-feature-settings for features not covered by the high-level API.
Ligatures
Ligatures are special glyphs that replace specific letter combinations to resolve spacing or optical collision problems. The classic examples are fi, fl, ff, ffi, and ffl — in most typefaces, the hook of the f collides with the dot of the i or the ascender of l. A ligature replaces these with a single custom glyph that reads correctly.
Standard Ligatures (liga)
Standard ligatures (fi, fl, etc.) are enabled by default in most browsers for most typefaces. Make this explicit:
body {
font-variant-ligatures: common-ligatures;
/* Or: font-feature-settings: "liga" 1, "clig" 1; */
}
Discretionary Ligatures (dlig)
Discretionary ligatures are decorative, not functional — combinations like st, ct, or Th given stylized joined forms. They are off by default and should be used selectively at display sizes:
.display-heading {
font-variant-ligatures: common-ligatures discretionary-ligatures;
/* Or: font-feature-settings: "liga" 1, "dlig" 1; */
}
Use discretionary ligatures in headings and display text; avoid in body copy where they can disrupt reading rhythm.
Small Caps (smcp, c2sc)
Small caps are capital letters drawn to approximately x-height — they are optically sized capitals, not mechanically scaled-down ones. Fake small caps (CSS font-size: 0.8em; text-transform: uppercase) produce thin, weak letterforms that betray the effect. Real small caps (smcp) are designed at x-height with appropriate weight.
Use small caps for:
- Author bylines and section labels within text ("By Robert Bringhurst" in true small caps)
- Roman numerals in running text
- Acronyms and initialisms (NASA, HTTP) to prevent them shouting relative to surrounding text
/* True small caps for inline acronyms */
abbr {
font-variant-caps: small-caps;
font-variant-ligatures: no-common-ligatures; /* Ligatures in caps can look odd */
letter-spacing: 0.04em; /* Open slightly — all-caps rule applies */
/* Or: font-feature-settings: "smcp" 1; */
}
/* Convert capitals to small caps */
.byline {
font-variant-caps: all-small-caps; /* Converts both upper and lower */
/* Or: font-feature-settings: "c2sc" 1, "smcp" 1; */
}
Numeric Styles
This is where OpenType features have the most immediate practical impact in product and editorial design.
Oldstyle Figures (onum)
Oldstyle figures (also called text figures) have varying heights — some ascend above the x-height, some descend below the baseline — mimicking the behavior of lowercase letters. They integrate into running text without disturbing the visual rhythm:
/* Oldstyle figures in body text */
body, p, li {
font-variant-numeric: oldstyle-nums;
/* Or: font-feature-settings: "onum" 1; */
}
Oldstyle figures are preferable in flowing text. Use lining figures (the default) in financial tables, headings, and any context where numbers appear in isolation rather than within prose.
Lining Figures (lnum)
Lining figures sit uniformly between the baseline and cap height — all the same height. They are appropriate for tables, financial data, form fields, and any context where numbers appear in isolation:
.financial-table td,
.price,
.stat-value {
font-variant-numeric: lining-nums;
/* Or: font-feature-settings: "lnum" 1; */
}
Tabular Figures (tnum)
Tabular figures give every numeral identical advance width so that numbers in a column align vertically. This is separate from lining vs. oldstyle — either style can be tabular or proportional.
For any numerical data in a table or aligned list, use tabular figures:
.data-table td,
.price-column {
font-variant-numeric: tabular-nums lining-nums;
/* Or: font-feature-settings: "tnum" 1, "lnum" 1; */
}
Tabular figures are particularly important for product prices, statistics dashboards, and financial interfaces where numbers change dynamically — without tabular figures, a column of numbers will shift its alignment as values change.
Fractions (frac)
.recipe-measurement {
font-variant-numeric: diagonal-fractions;
/* Or: font-feature-settings: "frac" 1; */
}
/* Transforms "1/2" into a proper diagonal fraction glyph */
Ordinals (ordn)
/* "1st", "2nd", "3rd" with proper superscript characters */
.ordinal {
font-feature-settings: "ordn" 1;
}
Stylistic Sets (ss01–ss20)
Many typefaces include stylistic sets — groups of alternate glyphs that change the visual character of the typeface without altering its fundamental design. A stylistic set might provide alternate lowercase a or g forms, alternative decorative capitals, or modified punctuation shapes.
The available stylistic sets are typeface-specific — check the specimen or documentation for each typeface to discover what its sets contain. For example, in some versions of Recursive:
/* Typeface-specific — always check the documentation */
.mono-code {
font-feature-settings: "ss01" 1; /* Alternate 'a' form in some typefaces */
}
A Production-Ready font-variant Stack
Combining these features into a working body text baseline:
body {
/* Core text features */
font-variant-ligatures: common-ligatures contextual;
font-variant-numeric: oldstyle-nums proportional-nums;
font-kerning: normal;
font-optical-sizing: auto;
text-rendering: optimizeLegibility;
}
/* Tables and financial data override */
table, .data-display {
font-variant-numeric: lining-nums tabular-nums;
}
/* Display headings */
h1, h2, .hero-title {
font-variant-ligatures: common-ligatures discretionary-ligatures;
font-variant-caps: normal; /* Reset any inherited small caps */
font-kerning: normal;
}
/* Abbreviations and acronyms */
abbr[title] {
font-variant-caps: all-small-caps;
letter-spacing: 0.04em;
text-decoration: underline dotted;
}
Key Takeaways
- OpenType features are accessed in CSS via
font-variant-*(preferred) andfont-feature-settings - Standard ligatures (
liga) are on by default; discretionary ligatures (dlig) should be added for display text - Use oldstyle figures (
onum) in body text, lining figures (lnum) in tables and isolated numerical display - Tabular figures (
tnum) ensure numerical columns align — essential for any data table or price display - True small caps (
smcp) require a typeface with real small cap glyphs; fake small caps look wrong - Check the specimen documentation for each typeface to discover available stylistic sets