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.
Typographic Details Cheat Sheet
Click here to view the experiment on Codepen
The font-variant- Properties for Advanced Typography
Link to this sectionYou 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 sectionLigatures 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
Link to this sectionThe 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
Link to this sectionA 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
Link to this sectionThe 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
Link to this sectionFonts 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 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)
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
Link to this sectionThere 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: