Introducing Normalize-OpenType.css

OpenType features make it possible for type designers to include language requirements, and typographic niceties—ligatures, alternate figures, small caps—within a font.

These design decisions are one reason certain type families are much more useful and versatile than others, yet the features they include are usually ignored on the web. I’m hoping that will happen a little less often with Normalize-OpenType.css.

The typeface Lavanderia’s OpenType features are highlighted.

James T. Edmondson’s Lavanderia uses OpenType features to recreate a script’s inconsistencies, and includes alternate that designers can choose to use.

It’s possible to enable these OpenType features in CSS through the font-feature-settings property. It has respectable browser support, but is difficult to get started with.

One reason for this is the inconsistent or undefined browser defaults: almost everything is turned off even when that isn’t the typographically correct decision.


This is a familiar situation within CSS: a predictable base across browsers is necessary, with expected defaults set in advance. Normalize.css accomplishes this by correcting browser inconsistencies, leaving expected defaults in place, and setting the correct ones elsewhere: <strong> should be bolded, <body> shouldn’t have a margin, etc.

A similar starting point for these OpenType features could be used, correcting font-feature-settings browser inconsistencies, leaving expected defaults in place, and setting the typographically correct ones elsewhere.

I’m working on this problem as an extension to Normalize.css, which is now available as Normalize-OpenType.css

Normalizing OpenType features

Following the same normalising approach as its namesake, Normalize-OpenType.css only includes CSS that applies OpenType features to basic HTML elements, like <body>, <table>, and <time>.

If your font includes OpenType features, your typography will be improved in supported browsers. If not, nothing else will be affected.


With Normalize-OpenType.css, kerning will be turned on for the <body> element.

body {
  font-feature-settings: "kern";

This works, but doesn’t necessarily continue to if font-feature-settings is being used in multiple places within the stylesheet.

Faking the levels

Unfortunately, previous font-feature-settings are overwritten when the property is re-applied:

body {
  font-feature-settings: "kern";

h1 {
  font-feature-settings: "dlig";
  /* Kerning wasn’t specified, and therefore may be off. */

This occurs because font-feature-settings is a high-level CSS property, like background or margin. Normally, it’s possible to use a low-level property instead, like background-color or margin-left. This should leave the previous defaults in place.

Due to a lack of browser support, this isn’t possible with font-feature-settings. Almost every one of its low-level variants remains unsupported.

Returning to kerning

The way around this browser support issue is through repetition:

body {
  font-feature-settings: "kern";

h1 {
  font-feature-settings: "kern", "dlig";
  /* Kerning is manually turned on, too */

Normalize-OpenType.css’ actual font-feature-settings declaration on the <body> is longer, but the approach is the same. I’ve omitted the repetitive CSS from the examples, but the full version is commented in the stylesheet itself.

The same approach is applied to other OpenType features, like ligatures.

Basic Ligatures

Ligatures can solve layout problems, like changing f f into an ff ligature, where the glyphs would awkwardly overlap otherwise. They can also be included to add character to a typeface, or to make a script font more convincing.

Ligatures are good, no ligatures not so good

Once ligatures are turned on, you’ll see additional glyphs like this ffi in fantastic typefaces like Klinic Slab.

With Normalize-OpenType.css, basic ligatures are turned on all the time:

body {
  font-feature-settings: "liga", "kern";

Additional ligatures, less common for text settings, are also be enabled.

Discretionary Ligatures

Discretionary ligatures tend to draw a little more attention to themselves, and they’re generally only appropriate for larger text sizes.

Headings receive discretionary ligatures

Klinic Slab includes a discretionary st ligature, but this will vary from one typeface to another.

In Normalize-OpenType.css, discretionary ligatures are enabled for large headings:

h1, h2, h3 {
  font-feature-settings: "dlig";


There are situations where different numerals are necessary, sometimes based on width requirements, and other times on height requirements. Not every typeface will contain all variations, but Normalize-OpenType.css will make sure you have the most appropriate version that is present in the font.

Proportional numeric figures are designed to take up whatever width they need. Tabular numerals are monospaced, so they can be easily compared while stacked vertically.

Example showing how Tabular figures are applied

Tabular, Lining figures, shown here, are pretty good at the whole tables thing.

This is applied in a few places in the CSS, like on tables themselves:

table {
  font-feature-settings: "tnum", "pnum" off;
  /* Turn on Tabular figures, but also explicitly
  turn off Proportional figures. */

Typefaces may also include Lining and Old-Style figures. The former are the numbers you are probably most used to seeing: they match the height of the capitals.

Example showing how Old-Style numerals are applied

Old Style, Proportional figures, used inline.

These are applied to the <body> in the CSS:

body {
  font-feature-settings: "onum", "lnum" off;
  /* Turn on Old-Style figures, but also explicitly
  turn off Lining figures. */

Old-Style numerals are actually more appropriate for most situations, especially when setting body text; they are less distracting while inline. This is also true of Small Caps.

Small Caps & Case Sensitive Forms

Small Caps and alternate punctuation marks that are meant to go with them are automatically applied to <abbr> elements. This makes all-caps phrases less intrusive within body text, which can be especially effective with Typogrify, Typogr.js, or similar libraries that find where Small Caps should go.

Example showing how Small Caps are used

Small Caps are less distracting than all capitals.

It’s worth noting that some font service providers have chosen to make small caps an separate font. This means the small caps aren’t included in the main font as OpenType features, so Normalize-OpenType.css can’t help. These services will likely embrace font-feature-settings more in the future, and stop creating separate fonts for single features as it’s no longer necessary.

What it can’t assume

There are other OpenType features that a Normalize-OpenType.css can’t take advantage of:

  • Titling caps
  • Stylistic sets
  • Contextual alternates

…and many, many more need to be applied on a case-by-case basis. Typotheque’s slightly outdated but still very useful article on OpenType features in the browser and Elliot Jay Stocks’ The fine flourish of the ligature are both worthy articles on that subject.


Normalize-OpenType.css is available on GitHub under the MIT license. The latest version of the CSS file itself is also available.