@font-feature-values

Juan Diego Rodríguez on

Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.

The @font-feature-values at-rule gives a human-readable name to the font’s settings declared in the font-feature-settings property, such as style sets, ornaments, and swashes. Since similar feature settings vary from font to font, @font-feature-values groups them under a common name. This new name can then be applied with the font-variant-alternates property.

/* Define the feature values with a name */
@font-feature-values Noble Company {
  @stylistic {
    curly: 1; /* Sets salt 1 on */
  }
}

h1 {
  font-family: Noble Company;
  font-variant-alternates: stylistic(curly); /* Apply the features */
}

The @font-feature-values at-rule is defined in the CSS Fonts Module Level 4 specification.

Syntax

@font-feature-values = @font-feature-values <family-name># { <declaration-rule-list> }

@historical-forms = @historical-forms { <declaration-list> }
@stylistic = @stylistic { <declaration-list> }
@styleset = @styleset { <declaration-list> }
@character-variant = @character-variant { <declaration-list> }
@swash = @swash { <declaration-list> }
@ornaments = @ornaments { <declaration-list> }
@annotation = @annotation { <declaration-list> }

Arguments, rules and descriptors

  • <family-name>: This is the font family the font features apply to.
  • @stylistic: This sets the index for stylistic alternates, which match the OpenType salt feature tag.
  • @styleset: This sets the index for stylistic sets, which match the OpenType ss01 to ss20 feature tag.
  • @character-variant: This sets the index of specific character variants, which match OpenType cv01 to cv99 feature tag.
  • @swash: This sets the index of swash glyphs, which match the OpenType swsh feature tag.
  • @ornaments: This sets the index of default glyphs with ornaments, which match the OpenType ornm feature tag.
  • @annotation: This sets the index of alternate annotation forms, which match the OpenType nalt feature tag.

While a @historical-forms rule exists, its usage is redundant since font-variant-alternates takes a historical-forms keyword, not a function.

Why @font-feature-values?

To understand why we need @font-feature-values we talk about what a font feature is and how they workk with the font-feature-settings property.

You may have heard about the OpenType format and how it’s considered the uppermost font format. On the web, we use them all the time, mainly as .woff and .woff2 files, which work as compressed wrappers for OpenType (and TrueType) fonts.

But why is OpenType considered so good? It has many technical improvements from past formats. Still, from a web design perspective, it allows font designers to save different glyphs of the same character for different situations, which can then be picked by the web designer/developer. For example, the same OpenType font could have alternate glyphs for the letter “A”.

Different Alternates for the letter "A"

This is just one of many examples; an OpenType font could have alternates for kerningligaturesswashes, and many other variants that can be picked by the font user. These variations on the same font are called font features.

In CSS, there are many ways to enable a font feature. First, common font features have their own font properties. For example, the font’s kerning and ligatures can be enabled through the font-kerning and font-variant-ligatures properties. But this isn’t true for most features, so we have to enable them through the font-feature-settings property.

The font-feature-settings property takes a list of tuples, each made of the font feature we want to enable and an index. The font feature is written as a four-letter string, while the index is just an integer that turns on the feature.

.element {
  font-feature-settings: "kern" 0, "swsh" 1;
  /* Sets kerning off and swashes on */
}

Some features can simply be turned on and off, in which case the 0 index disables them and 1 enables them. However, some fonts can have more than one state, for example, instead of enabling all swashes, the "swsh" 1 could enable the swash for a group of characters, "swsh" 2 another group, and so on.

This leads us to the most important concept: font features aren’t standard! So what "swsh 1" means may change from font to font; it could even do nothing in some fonts, which is why font-feature-settings is generally discouraged. You don’t always know which features a font file supports and need to use a tool like Wakamai Fondue to expose them.

Here is where @font-feature-values comes in. For a specific font, the at-rule assigns a human-readable name to a set of font features. You can then think of @font-feature-values as a shortcut for font-feature-settings. We can have several @font-feature-values for different fonts under the same name, and this way, if the font-family changes, then the browser will pick the correct @font-feature-values for that font.

For a detailed explanation of each font feature accessible through @font-feature-values, check the font-variant-alternates property.

Basic usage

First, we will need an OpenType font with some font features to play with. I’ll be using The Melody by Riza Haitami. We can know exactly which features it supports using the Wakamai Fondue tool, which returns us the following features:

The Melody Available Features

If we inspect further, we’ll see it has a salt (Stylistic Alternates) available feature, which is turned off by default.

The Melody Salt Feature

However, just setting salt 1 through font-feature-settings doesn’t give us a lot of information on what we are exactly doing to the font. Instead, we can use @font-feature-values and give it a name. In this case, the salt feature appears to give the characters a decorative tail, so I am going to name this set of features tails. We name it with the @stylistic rule, which is in charge of setting the index for salt features.

@font-feature-values Melody {
  @stylistic {
    tails: 1; /* Sets salt to 1, which enables it */
  }
}

And to apply it to an element, we will use the font-variant-alternates property. It takes a function with the same name as the rule we used (stylistic() in this specific example) and the feature name as an argument (tails in this example).

h1 {
  font-family: Melody;
  font-variant-alternates: stylistic(tails);
}

The @font-feature-values at-rule shines when we have several fonts with similar font features but under different indexes. For example, both the Andior by Yudi Pratama Chandra and Denhils by Burhan Afif fonts have a font feature that enables “tails”. However, Andior has the feature listed under ss03, while Denhils has it under ss04:

Andior ss03 feature
Denhils ss04 feature

So, if we used font-feature-settings to enable the feature for an element, it would mess up the text if the font-family changes from one another. Using @font-feature-values, we can set the correct feature index under the same tails name. This time using the @styleset at-rule which sets the index for ssXX features:

@font-feature-values Andior {
  @styleset {
    tails: 3; /* Enables ss03 */
  }
}

@font-feature-values Denhils {
  @styleset {
    tails: 4; /* Enables ss04 */
  }
}

Then the browser will enable the correct feature based on the font-family:

.andior {
  font-family: "Andior";
  font-variant-alternates: styleset(tails);
}

.denhils {
  font-family: "Denhils";
  font-variant-alternates: styleset(tails);
}

We could also have several features defined on the same rule:

@font-feature-values Skrine {
  @styleset {
    backtail: 1; /* sets ss01 on */
    fronttail: 2; /* sets ss02 on */
    pigtail: 3; /* sets ss03 on */
    fancy: 6; /* sets ss06 on */
  }
}

Specification

The @font-feature-values at-rule is defined in the CSS Fonts Module Level 4 specification, which is currently in Editor’s Draft.

Browser support

Both the/ and the font-variant-alternates are supported on all browsers.

More information