</>Jonathan Harrell

Main Menu

Site Tools

Better Typography with Font Variants

Typography on the web has always lagged behind its expression in print. This makes sense, as type on the printed page developed over centuries to a point of complexity that has been hard to capture within the confines of a browser.

However, this is quickly changing thanks to the increasing availability of OpenType features in web fonts and the ability to control those features with CSS.

This article is an overview of how to control OpenType features using CSS, but remember that whatever web font you are using will also need to support these features.

Go to experiment

Typographic Details Cheat Sheet

Click here to view the experiment on Codepen

The font-variant- Properties for Advanced Typography

Link to this section

You can control most OpenType features using various properties beginning with font-variant-. There is also a low-level property font-feature-settings which can be used to support legacy browsers. Whenever possible, however, you should use the more modern font-variant properties. One solution is to use an @supports rule to check if a font-variant property is supported and otherwise use font-feature-settings.

body {
  font-feature-settings: "liga" 1;
}

@supports (font-variant-ligatures: common-ligatures) {
  body {
    font-feature-settings: normal;
    font-variant-ligatures: common-ligatures;
  }
}

font-variant-ligatures

Link to this section

Ligatures are single glyphs made from two or more characters. They typically prevent ugly or awkward letter collisions and, therefore, aid legibility.

common-ligatures

Common ligatures often include character pairings where the first letter is "f".

These are ligatures that the type designer has decided should be used in normal conditions. In most circumstances you should use these. Most browsers enable them by default.

font-variant-ligatures: common-ligatures; /* enable */
font-variant-ligatures: no-common-ligatures; /* disable */

font-feature-settings: 'liga' 1; /* low-level enable */
font-feature-settings: 'liga' 0; /* low-level disable */

discretionary-ligatures

Discretionary ligatures can include character pairings with flourished connections.

These are ligatures which can be used for typographic purposes, for example to achieve a special effect. These are disabled by default.

font-variant-ligatures: discretionary-ligatures; /* enable */
font-variant-ligatures: no-discretionary-ligatures; /* disable */

font-feature-settings: 'dlig' 1; /* low-level enable */
font-feature-settings: 'dlig' 0; /* low-level disable */

contextual

In the Inkwell Script typeface, alternate versions of the letters "f" and "t" are automatically introduced.

These are alternate ligatures that are affected by their surrounding context. They often harmonize the shapes of grouped glyphs. These are enabled by default.

font-variant-ligatures: contextual; /* enable */
font-variant-ligatures: no-contextual; /* disable */

font-feature-settings: 'calt' 1; /* low-level enable */
font-feature-settings: 'calt' 0; /* low-level disable */

historical-ligatures

Alternate characters like the archaic "long s" can be used in historical settings.

These are ligatures which could be considered a subset of discretionary, but are specifically used to achieve a historical effect. These are disabled by default.

font-variant-ligatures: historical-ligatures; /* enable */
font-variant-ligatures: no-historical-ligatures; /* disable */

font-feature-settings: 'hlig' 1; /* low-level enable */
font-feature-settings: 'hlig' 0; /* low-level disable */

font-variant-position

Link to this section

The proper markup for subscripts and superscripts uses the sub and sup elements. By default, browsers take a regular numeral character, make it smaller using font-size, and raise or lower it with vertical-align. These are not true subscript and superscript characters and typically appear quite ugly, not to mention they can mess up line height.

Thankfully, there is now a way to enable true subscripts and superscripts with font-variant-position. Note that currently only Firefox supports this.

sub

True subscript characters are sized and positioned specifically for use in footnotes and scientific formulas.

This enables true subscript characters.

font-variant-position: sub; /* enable */
font-variant-position: normal; /* disable both variants */

font-feature-settings: 'subs' 1; /* low-level enable */
font-feature-settings: 'subs' 0; /* low-level disable */

super

True superscript characters are sized and positioned specifically for use in mathematical expressions and scientific formulas.

This enables true superscript characters.

font-variant-position: super; /* enable */
font-variant-position: normal; /* disable both variants */

font-feature-settings: 'sups' 1; /* low-level enable */
font-feature-settings: 'sups' 0; /* low-level disable */

font-variant-caps

Link to this section

A capital is not a capital is not a capital. The most significant use of font-variant-caps is to enable small caps, although there are several other options available.

small-caps

Small caps in the typeface Hoefler Text match the x-height of the font.

Small caps are designed to be the same height as lowercase letters and are used to capitalize words within running text. They make for a more cohesive and readable paragraph.

font-variant-caps: small-caps;  /* enable */
font-variant-caps: normal; /* disable all variants */

font-feature-settings: 'smcp' 1; /* low-level enable */
font-feature-settings: 'smcp' 0; /* low-level disable */

all-small-caps

All characters in the typeface Hoefler Text are converted to small caps using all-small-caps.

The small-caps value will only replace lowercase letters with small caps. To replace all letters with small caps (which is probably what you want) you need to use all-small-caps.

font-variant-caps: all-small-caps; /* enable */
font-variant-caps: normal; /* disable all variants */

font-feature-settings: 'smcp' 1, 'c2sc' 1; /* low-level enable */
font-feature-settings: 'smcp' 1, 'c2sc' 0; /* low-level disable */

petite-caps

Petite caps in the typeface EB Garamond are slightly shorter than the x-height of the font.

Standard small caps will typically appear slightly larger than the x-height of the font. Some typefaces have additional small caps that match the x-height. These are called petite-caps.

font-variant-caps: petite-caps; /* enable */
font-variant-caps: normal; /* disable all variants */

font-feature-settings: 'pcap' 1; /* low-level enable */
font-feature-settings: 'pcap' 0; /* low-level disable */

all-petite-caps

All characters in the typeface EB Garamond are converted to petite caps using all-petite-caps.

Similarly to all-small-caps, this converts all letters, both lower and uppercase, to petite caps.

font-variant-caps: all-petite-caps; /* enable */
font-variant-caps: normal; /* disable all variants */

font-feature-settings: 'pcap' 1, 'c2pc' 1; /* low-level enable */
font-feature-settings: 'pcap' 1, 'c2pc' 0; /* low-level disable */

unicase

A version of the Arial typeface includes unicase characters.

This feature maps upper and lowercase letters to a mixed set of lowercase and small capital forms, creating a single case alphabet. Sometimes the small capitals used are actual small cap glyphs and sometimes they are specially designed unicase forms. The implementation of this feature varies greatly from font to font.

font-variant-caps: unicase; /* enable */
font-variant-caps: normal; /* disable all variants */

font-feature-settings: 'unic' 1; /* low-level enable */
font-feature-settings: 'unic' 0; /* low-level disable */

titling-caps

Titling caps are designed for headline sizes, similar to the Hoefler Titling typeface.

Standard uppercase letters are designed for use alongside lowercase letters and when they are used in strings of all uppercase letters they can appear too strong. Some fonts include titling capitals specifically for this situation.

font-variant-caps: titling-caps; /* enable */
font-variant-caps: normal; /* disable all variants */

font-feature-settings: 'titl' 1; /* low-level enable */
font-feature-settings: 'titl' 0; /* low-level disable */

font-variant-numeric

Link to this section

The proper display of numerals varies greatly depending on context. Here are some general rules:

  • In running/body text, use proportional old-style numerals
  • For headings, use proportional lining numerals
  • Within numeric tables, use tabular lining numerals

You can combine values to achieve, for example, tabular lining numerals like this:

font-variant-numeric: lining-nums tabular-nums;

lining-nums

Lining numerals in the typeface Ideal Sans stretch from baseline to cap-height.

Lining numerals approximate capital letters and are uniform in height. They should be used in headings or numeric tables. Usually numbers are lining figures by default.

font-variant-numeric: lining-nums; /* enable */
font-variant-numeric: normal; /* disable all variants */

font-feature-settings: 'lnum' 1; /* low-level enable */
font-feature-settings: 'lnum' 0; /* low-level disable */

oldstyle-nums

Old-style numerals in the typeface Ideal Sans ascend and descend to sympathize with the rhythm of lowercase letters.

Old-style numerals have varying heights and alignments and are therefore more similar to lowercase letters. They should be used in running text.

font-variant-numeric: oldstyle-nums; /* enable */
font-variant-numeric: normal; /* disable all variants */

font-feature-settings: 'onum' 1; /* low-level enable */
font-feature-settings: 'onum' 0; /* low-level disable */

proportional-nums

Proportional numerals have variable spacing and blend in with horizontal text. They should be used in most situations, other than numeric tables where vertical alignment is important. Usually numbers are proportional figures by default.

font-variant-numeric: proportional-nums; /* enable */
font-variant-numeric: normal; /* disable all variants */

font-feature-settings: 'pnum' 1; /* low-level enable */
font-feature-settings: 'pnum' 0; /* low-level disable */

tabular-nums

Tabular numerals should be used in contexts where numbers need to be stacked.

Tabular numerals have the same width and should be used in numeric tables to allow vertical alignment of numbers.

font-variant-numeric: tabular-nums; /* enable */
font-variant-numeric: normal; /* disable all variants */

font-feature-settings: 'tnum' 1; /* low-level enable */
font-feature-settings: 'tnum' 0; /* low-level disable */

diagonal-fractions

Numerators and denominators in the typeface Ideal Sans are aligned with the baseline and cap-height.

By default, fractions will display as lowercase letters with a slash. Proper fractions will be formatted to match the height of a lining figure and can be either diagonal or stacked.

font-variant-numeric: diagonal-fractions; /* enable */
font-variant-numeric: normal; /* disable all variants */

font-feature-settings: 'frac' 1; /* low-level enable */
font-feature-settings: 'frac' 0; /* low-level disable */

stacked-fractions

Numerators and denominators are horizontally aligned in stacked fraction alternates.

Stacked fractions are not as common of a feature in most web fonts as diagonal fractions, but should prove useful with heavily scientific or mathematical content.

font-variant-numeric: stacked-fractions; /* enable */
font-variant-numeric: normal; /* disable all variants */

font-feature-settings: 'afrc' 1; /* low-level enable */
font-feature-settings: 'afrc' 0; /* low-level disable */

ordinal

The typeface Fedra Sans includes specially sized and positioned characters for common ordinals like "1st", "2nd", and "3rd".

Ordinals like st, nd, rd, and th will appear as standard lowercase letters by default. However, these should ideally appear as smaller raised numbers following the numeral. The ordinal value enables that.

font-variant-numeric: ordinal; /* enable */
font-variant-numeric: normal; /* disable all variants */

font-feature-settings: 'ordn' 1; /* low-level enable */
font-feature-settings: 'ordn' 0; /* low-level disable */

slashed-zero

The typeface Operator Mono includes a special slashed-zero numeral.

This enables an alternate zero character with a slash through it.

font-variant-numeric: slashed-zero; /* enable */
font-variant-numeric: normal; /* disable all variants */

font-feature-settings: 'zero' 1; /* low-level enable */
font-feature-settings: 'zero' 0; /* low-level disable */

font-variant-alternates

Link to this section

Fonts can provide a variety of alternates for any character. The font-variant-alternates property provides many ways of controlling this character substitution.

historical-forms

The typeface Hoefler Text provides an historical alternate "s" character, known as the archaic "long s".

Historical alternates can be used for a “period” effect. Note the difference between this and historical ligatures. Historical ligatures are historical character combinations, whereas historical forms are substitutions for individual characters.

font-variant-alternates: historical-forms; /* enable */
font-variant-alternates: normal; /* disable all variants */

font-feature-settings: 'hist' 1; /* low-level enable */
font-feature-settings: 'hist' 0; /* low-level disable */

stylistic(feature-value-name)

The typeface Ideal Sans includes several special characters and alernates, such as the Inscriptional "G".

Use this to select stylistic features on an individual basis. In order to use this and several of the following font-variant-alternates functions, you must define a font-feature-value using the @font-feature-values rule. For example, if you wanted to select stylistic feature number 1 in the font you are using, you would first define the feature value, and then use it within the font-variant-alternates: stylistic() function.

@font-feature-values 'typeface-name' {
  @stylistic { inscriptional-g: 1 }
}

font-variant-alternates: stylistic(inscriptional-g); /* enable */
font-variant-alternates: normal; /* disable all variants */

font-feature-settings: salt 1; /* low-level enable */
font-feature-settings: salt 0; /* low-level disable */

styleset(feature-value-name)

Stylesets in the typeface Hoefler Text allow you to apply related alternate characters.

Use this to select an entire set of alternative glyphs. The glyphs in a set are often designed to work together. Select a particular set by defining a font-feature-values rule using the set’s number.

@font-feature-values 'typeface-name' {
  @styleset { special-styleset: 1 }
}

font-variant-alternates: styleset(special-styleset); /* enable */
font-variant-alternates: normal; /* disable all variants */

font-feature-settings: ss01; /* low-level enable */

character-variant(feature-value-name)

The italic style of the typeface Hoefler Text includes variants for several characters, including the letters "k" and "z".

Use this to select specific character variants. Select a particular variant by defining a font-feature-values rule using the variant’s number.

@font-feature-values 'typeface-name' {
  @character-variant { special-variant: 1 }
}

font-variant-alternates: character-variant(special-variant); /* enable */
font-variant-alternates: normal; /* disable all variants */

font-feature-settings: cv01; /* low-level enable */

swash(feature-value-name)

The typeface Hoefler Text includes alternate italic swash caps for several characters, including "M".

Swashes can be used to provide typographic interest to headings or more artistic settings of text. They are typically exaggerated alternative character designs, or have some sort of typographic flourish. Select a particular swash by defining a font-feature-values rule using the set’s number.

@font-feature-values 'typeface-name' {
  @swash { flourish: 1 }
}

font-variant-alternates: swash(flourish); /* enable */
font-variant-alternates: normal; /* disable all variants */

font-feature-settings: swsh 1; /* low-level enable */
font-feature-settings: swsh 0; /* low-level disable */

ornaments(feature-value-name)

The typeface Hoefler Text provides many graphic characters, including several fleurons.

This replaces default glyphs with ornaments, if they are provided in the font.

@font-feature-values 'typeface-name' {
  @ornaments { fleurons: 1 }
}

font-variant-alternates: ornaments(fleurons); /* enable */
font-variant-alternates: normal; /* disable all variants */

font-feature-settings: ornm 1; /* low-level enable */
font-feature-settings: ornm 0; /* low-level disable */

annotation(feature-value-name)

The collection of Whitney Index fonts provide examples of annotation characters.

Annotations are notational forms of glyphs (for example, glyphs placed in open or solid circles, squares, parentheses, diamonds, rounded boxes. etc.).

@font-feature-values 'typeface-name' {
  @ornaments { circles: 1 }
}

font-variant-alternates: annotation(circles); /* enable */
font-variant-alternates: normal; /* disable all variants */

font-feature-settings: nalt 1; /* low-level enable */
font-feature-settings: nalt 0; /* low-level disable */

Further Web Typography Resources

Link to this section

There is a huge amount to learn about typography on the web including font variants and much more. Check out the following excellent resources for more information:

More Articles

Go to article

System-Based Theming with Styled Components

Learn how to support system-based theming in Styled Components, while allowing a user to select their preferred theme and persist that choice.

Go to article

Implicit State Sharing in React & Vue

Learn to use React’s Context API and provide/inject in Vue to share state between related components without resorting to a global data store.

Go to article

Component Reusability in React & Vue

Learn how to use render props in React and scoped slots in Vue to create components that are flexible and reusable.

Go to article

What’s the Deal with Margin Collapse?

Learn about margin collapse, a fundamental concept of CSS layout. See visual examples of when margin collapse happens, and when it doesn’t.