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.

For live examples, check out my web typography cheat sheet here.

The font-variant- Properties for Advanced Typography

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

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

common-ligatures

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

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

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

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

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

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

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

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 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

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

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

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

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

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

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 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 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 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

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

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

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

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

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

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)

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)

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)

Use this to select specific character variants. Select a particular variant by defining a font-feature-values rule using the set’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)

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)

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)

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

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: