Type something to search...
What are OpenType features and how do you enable them in CSS?

What are OpenType features and how do you enable them in CSS?

OpenType features are optional typographic behaviours built into a font file, such as ligatures, true small caps, different styles of numerals, automatic fractions, alternate letter shapes and kerning. Each feature has a four-letter tag, for example liga for standard ligatures, smcp for small caps and tnum for tabular numbers. A few features, including kerning and standard ligatures, are switched on by default in browsers, but most are off until you ask for them. In CSS, you enable them with the high-level font-variant-* properties, such as font-variant-numeric: tabular-nums or font-variant-caps: small-caps, or with the low-level font-feature-settings property when no high-level equivalent exists. Features only work if the font actually contains them, so the first step is always to check what your font supports.

Most web fonts contain far more than the basic alphabet. Well-made families include carefully drawn alternatives that improve readability, make tables line up, and give your text a more polished finish, yet many sites never use them. In this article you'll learn how OpenType features work, which ones are worth knowing, how to find out what a font supports, how to enable features with the right CSS property, and how to avoid the common mistakes that cause features to be lost.

How OpenType Features Work

An OpenType font contains glyph substitution and positioning rules, stored in two tables:

  • GSUB (glyph substitution): Replaces one or more glyphs with others. Ligatures swap "f" and "i" for a single "fi" glyph, small caps swap lowercase letters for small capital forms, and stylistic sets swap a letter for an alternative design.
  • GPOS (glyph positioning): Moves glyphs relative to each other. Kerning adjusts the space between specific pairs, and mark positioning places accents correctly.

Each set of rules is grouped under a feature tag. When the browser shapes text, it applies the rules for every feature that's active. The underlying characters in your HTML don't change, so copying, searching and screen readers still see the original text. Only the glyphs drawn on screen are different.

Features Worth Knowing

There are dozens of registered features. These are the ones you'll use most often on the web:

TagNameWhat it doesOn by default
kernKerningAdjusts spacing between letter pairsYes
ligaStandard ligaturesJoins pairs like fi and flYes
caltContextual alternatesChanges glyphs based on neighboursYes
dligDiscretionary ligaturesDecorative ligatures like ct and stNo
smcpSmall capsLowercase to small capitalsNo
c2scCapitals to small capsUppercase to small capitalsNo
onumOld-style figuresNumerals with ascenders and descendersNo
lnumLining figuresNumerals at cap heightDepends on font
tnumTabular figuresEqual-width numeralsNo
pnumProportional figuresNumerals with natural widthsDepends on font
fracFractionsTurns 1/2 into a proper fractionNo
zeroSlashed zeroDistinguishes 0 from ONo
sups / subsSuperscript / subscriptProperly drawn small figuresNo
caseCase-sensitive formsAdjusts punctuation for all capsNo
ss01 to ss20Stylistic setsGroups of alternate designsNo
cv01 to cv99Character variantsAlternates for individual charactersNo

Not every font has every feature, and what a stylistic set does is up to the designer. In one font ss01 might give you a single-storey "a"; in another it might change the shape of the number 1.

How to Find Out What a Font Supports

Before writing CSS, check the font. There are three practical ways.

Read the Specimen

Good foundries and open-source projects document their features. Inter's website, for example, lists its character variants and stylistic sets with previews. Google Fonts specimen pages don't always list features, so you may need another method.

Use a Browser-Based Tool

Tools such as Wakamai Fondue let you drop a font file into the page and see every feature it contains, with examples and generated CSS. Nothing needs to be installed.

List Them With fontTools

If you prefer the command line, fontTools can read the feature tags directly:

pip install fonttools brotli
import sys
from fontTools.ttLib import TTFont

font = TTFont(sys.argv[1])
tags = set()

for table in ("GSUB", "GPOS"):
    if table in font and font[table].table.FeatureList:
        for record in font[table].table.FeatureList.FeatureRecord:
            tags.add(record.FeatureTag)

print(" ".join(sorted(tags)))

Save it as features.py and run it against your font:

python3 features.py fonts/SourceSerif4-Regular.woff2

The output is a list of tags, similar to this:

c2sc calt case dnom frac kern liga lnum mark mkmk numr onum ordn pnum smcp subs sups tnum

Subsetting tools sometimes strip features to save space. If a feature you expect is missing, check whether your build process removed it, and keep it with an option such as --layout-features+=smcp,onum in pyftsubset.

High-Level CSS Properties

CSS provides readable, well-supported properties for the most common features. Use these first.

font-variant-ligatures

.article {
  font-variant-ligatures: common-ligatures contextual;
}

.fancy-heading {
  font-variant-ligatures: common-ligatures discretionary-ligatures;
}

code {
  font-variant-ligatures: none;
}

Values include common-ligatures (liga), discretionary-ligatures (dlig), historical-ligatures (hlig), contextual (calt), their no- counterparts, and none.

font-variant-numeric

.prose {
  font-variant-numeric: oldstyle-nums proportional-nums;
}

table {
  font-variant-numeric: lining-nums tabular-nums;
}

.recipe-amount {
  font-variant-numeric: diagonal-fractions;
}

.serial-number {
  font-variant-numeric: slashed-zero;
}

You can combine one value from each group: figure style (lining-nums or oldstyle-nums), figure spacing (proportional-nums or tabular-nums), fractions (diagonal-fractions or stacked-fractions), plus ordinal and slashed-zero.

font-variant-caps

.byline {
  font-variant-caps: small-caps;
}

abbr {
  font-variant-caps: all-small-caps;
  letter-spacing: 0.04em;
}

small-caps turns lowercase letters into small capitals. all-small-caps does that and also converts capitals, which suits acronyms. There are also petite-caps, all-petite-caps, unicase and titling-caps, but few fonts include those forms.

font-variant-position

sup {
  font-variant-position: super;
}

sub {
  font-variant-position: sub;
}

These use the font's designed superscript and subscript glyphs. Support differs between browsers, and if the font lacks the glyphs, the result is normal-sized text. Many sites keep the default sup and sub styling for that reason.

font-variant-alternates

Stylistic sets and swashes can be given readable names with @font-feature-values:

@font-feature-values "Brand Sans" {
  @styleset {
    rounded-terminals: 1;
    simple-digits: 2;
  }
}

.ui-code {
  font-family: "Brand Sans", sans-serif;
  font-variant-alternates: styleset(simple-digits);
}

This is supported in current Chrome, Firefox and Safari, but it's newer than the other properties, so test before relying on it. The numbers map to ss01, ss02 and so on, and what each set does depends entirely on the font, so check its documentation for the real names and numbers.

font-kerning

body {
  font-kerning: normal;
}

Kerning is usually on by default. Set font-kerning: normal explicitly if you've seen it disabled for small text on some platforms.

The Low-Level font-feature-settings Property

font-feature-settings gives you direct access to any feature tag:

.ui {
  font-feature-settings: "cv05" 1, "cv08" 1, "ss03" 1;
}

h1 {
  font-feature-settings: "case" 1;
}

The syntax is a comma-separated list of quoted tags, each optionally followed by 1 (on) or 0 (off). A tag on its own means on.

Use it only when there's no high-level property, mainly for character variants (cvXX), stylistic sets when you don't want @font-feature-values, and features such as case. The reason is the same trap that affects font-variation-settings: any new declaration replaces the whole list.

body {
  font-feature-settings: "ss01" 1, "cv05" 1;
}

.price {
  /* ss01 and cv05 are now off for this element */
  font-feature-settings: "tnum" 1;
}

The high-level properties don't have this problem. Setting font-variant-numeric: tabular-nums on .price leaves any ligature or caps settings alone. If you do use font-feature-settings, keep the full list in a custom property so you can repeat it reliably:

:root {
  --base-features: "ss01" 1, "cv05" 1;
}

body {
  font-feature-settings: var(--base-features);
}

.price {
  font-feature-settings: var(--base-features), "tnum" 1;
}

Practical Recipes

Polished Article Text

.article {
  font-kerning: normal;
  font-variant-ligatures: common-ligatures contextual;
  font-variant-numeric: oldstyle-nums proportional-nums;
}

.article h1,
.article h2 {
  font-variant-numeric: lining-nums;
}

Data Tables and Dashboards

.data-table td,
.metric {
  font-variant-numeric: lining-nums tabular-nums slashed-zero;
}

All-Caps Labels

When labels are set in capitals with text-transform, case-sensitive forms raise hyphens, brackets and colons to suit capital letters:

.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-feature-settings: "case" 1;
}

Things That Turn Features Off

Several situations disable features without warning:

  • Letter spacing: Browsers turn off optional ligatures when letter-spacing isn't zero, because spaced-out ligatures look wrong.
  • Synthesised styles: If the browser fakes bold or italic, the synthetic face may not include the same features. Load real bold and italic files.
  • Subsetting: Aggressive subsetting can strip GSUB and GPOS rules.
  • Font services: Some hosted font services remove features from their default files. Check the service's documentation for an option to keep them.
  • Fallback fonts: If the browser falls back to a system font, your feature settings apply to that font instead, which may not have the same features.

For more detail on the low-level syntax and how it interacts with other properties, see how to use the font-feature-settings property.


FAQ: OpenType Features

It is a four-letter code that names a group of substitution or positioning rules inside a font, such as liga for ligatures or tnum for tabular numbers. CSS uses these tags to switch features on and off.

Kerning, standard ligatures and contextual alternates are normally enabled, along with features required for correct shaping of scripts such as Arabic. Most others, including small caps and tabular figures, are off until you enable them.

Use the font-variant properties whenever one covers the feature you need. They're easier to read and don't reset each other. Use font-feature-settings only for features without a high-level property, such as character variants.

The font may not contain it, the feature may have been removed during subsetting, a fallback font may be in use, or a later font-feature-settings declaration may have replaced your list. Check the font file first.

No. Features only change which glyphs are drawn. The characters in the HTML stay the same, so screen readers, search and copy and paste all work with the original text.

Many do, but it varies by family, and the files served for a specific subset may not include everything in the original font. Inspect the delivered file or self-host the full version if you need specific features.


Conclusion

OpenType features are the hidden layer of a good font: ligatures, small caps, figure styles, fractions, slashed zeros and alternate letterforms that the designer has already drawn for you. They live in the font's GSUB and GPOS tables, they don't alter the underlying text, and most of them stay switched off until you ask for them.

Check what your font contains with a specimen, a browser tool or a short fontTools script, then enable features with the high-level font-variant-ligatures, font-variant-numeric, font-variant-caps and related properties. Fall back to font-feature-settings only for features without a dedicated property, keep its list in one place, and watch for letter spacing, subsetting and fallback fonts quietly turning your features off.

Share :

Related Posts

How to make typography accessible?

How to make typography accessible?

You make typography accessible by choosing clear typefaces, setting text in relative units so it scales with user preferences, giving it enough colou

Dive Deeper
What are the parts of a letterform?

What are the parts of a letterform?

A letterform is the shape of a single letter, and typographers break it down into named parts. The main ones are the stem (the main vertical

Dive Deeper
What are ascenders, descenders and the baseline?

What are ascenders, descenders and the baseline?

The baseline is the invisible line that letters sit on. Ascenders are the parts of lowercase letters that rise above the x-height, such as th

Dive Deeper