Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.
The CSS font-variant-alternates
property lets you apply font features picked by the @font-feature-values
at-rule, such as style sets, ornaments, and swashes. Font features are font-specific, so font-variant-alternates
lets the browser know the correct feature to apply depending on the font-family
.
@font-feature-values Skrine {
@styleset {
pigtail: 4; /* Sets ss04 on */
}
}
h1 {
font-family: Skrine;
font-variant-alternates: styleset(pigtail);
}
The font-variant-alternates
property is defined in the CSS Fonts Module Level 4 specification.
Syntax
font-variant-alternates: normal | [ stylistic(<feature-value-name>) || historical-forms || styleset(<feature-value-name>#) || character-variant(<feature-value-name>#) || swash(<feature-value-name>) || ornaments(<feature-value-name>) || annotation(<feature-value-name>) ]
<feature-value-name> = <ident>
- Initial:
normal
- Applies to: all elements and text
- Inherited: yes
- Percentages: N/a
- Computed value: specified keyword
- Canonical order: per grammar
- Animation type: discrete
Values
font-variant-alternates: historical-forms;
font-variant-alternates: stylistic(tails);
font-variant-alternates: styleset(fancy);
font-variant-alternates: character-variant(g-foot);
font-variant-alternates: swash(fancy);
font-variant-alternates: ornaments(a-fleuron);
font-variant-alternates: annotation(circled-black);
normal
: No feature is enabled.historical-forms
: Enables historical forms, which match OpenTypehist
feature tag.stylistic()
: Enables stylistic alternates, which match the OpenTypesalt
feature tag.styleset()
: Enables stylistic sets, which match the OpenTypess01
toss20
feature tag.character-variant()
: Enables specific character variants, which match the OpenTypecv01
tocv99
feature tag.swash()
: Enables swash glyphs, which match the OpenTypeswsh
feature tag.ornaments()
: Enables default glyphs with ornaments, which match the OpenTypeornm
feature tag.annotation()
: Enables alternate annotation forms, which match the OpenTypenalt
feature tag.
Many font features!
You can think of @font-feature-values
and this entry as sister entries, so if you want to get a better picture of font features and why we need font-variant-alternates
, then I encourage you to check it. In the @font-feature-values
entry, we talked about OpenType fonts — a font format with many improvements, but whose main appeal was the ability to save different glyphs of the same character for different situations.

An OpenType font could have alternates for kerning, ligatures, swashes, and many other variants that can be picked by the font user. These variations on the same font are called font features.
There are many ways to set font features: some have their own property (such as font-kerning
), but many can only be changed manually. In the @font-feature-values
entry, we concluded that the best way to set those features was to define them through @font-feature-values
and then apply them through the font-variant-alternates
property.
However, we didn’t mention exactly what each font feature did but rather focused more on the syntax to set them. This time, we will look over each of the available font features in @font-feature-values
/font-variant-alternates
and what they do. Although we need to first recap their basic usage.
Basic usage
First, we will need an OpenType font with some font features to play with. I’ll be using Skrine by Gianstudio. We can know exactly which features are available in a font using the Wakamai Fondue tool, which returns us the following features:

Scrolling down, we’ll see a breakdown of each available font feature. In this case, I liked how the ss06
(Stylistic Set 06) feature gave the font a fancy look:

We can give that specific feature a common name using the @font-feature-values
at-rule. Since it’s a stylistic set feature, we’ll need the @styleset rule. Inside, we give it any name followed by the index of the feature we want to turn on:
@font-feature-values Skrine {
@styleset {
fancy: 6; /* Enables feature ss06 */
}
}
And to apply it to an element, we will use the font-variant-alternates
property. It takes a wrapper function with the same name as the rule we used (styleset()
) and the feature name as an argument.
h1 {
font-family: Skrine;
font-variant-alternates: styleset(fancy);
}
However, styleset()
is just one of the many features we can use inside font-variant-alternates
.
historical-forms
In the past, some letters had a different form than what they are today. The most known example is the Long s ⟨ſ⟩: an archaic version of the lowercase letter “s” which looks like a modern “f“. For that reason, some fonts have variable glyphs for historical letter forms (equivalent to the hist
feature tag), which can be enabled through the historical-forms
value.
h1 {
font-family: "Sorts Mill Goudy";
font-variant-alternates: historical-forms;
}
Notice how, unlike the following values, historical-forms
is a keyword and not a wrapper function, meaning it doesn’t have a useful equivalent rule in @font-feature-values
.
stylistic()
Stylistic alternates (equivalent to the salt
feature tag), are glyphs variations with an entirely stylistic purpose. This feature replaces the default forms with stylistic alternates.
@font-feature-values Melody {
@stylistic {
tails: 1; /* Sets salt to 1 */
}
}
h1 {
font-family: "Melody";
font-variant-alternates: stylistic(tails);
}
styleset()
While stylistic alternates usually affect all characters, some fonts have glyph variations that only affect a set of characters, hence the feature name stylistic set (equivalent to the ssXX
feature tag). Individual stylistic sets are named ssXX
, in which XX
refers to the set index and goes from ss01
to ss20
.
@font-feature-values Skrine {
@styleset {
fronttail: 1; /* Sets ss01 */
}
}
h1 {
font-family: "Skrine";
font-variant-alternates: styleset(fronttail);
}
character-variant()
Both stylistic alternates and stylistic sets apply to large sets of characters, so to apply a glyph variation for a specific character we will need to use the character variant (equivalent to the cvXX feature tag) feature. Individual character variants are named cvXX, in which XX refers to the variant index and goes from cv01
to cv99
.
@font-feature-values Inter {
@character-variant {
g-foot: 10; /* Sets cv10 */
}
}
h1 {
font-family: "Inter";
font-variant-alternates: character-variant(g-foot);
}
swash()
Swash symbols (equivalent to the swsh
feature tag), are glyphs with exaggerated details such as long serifs or tails. This feature replaces the default form with its swash versions.
@font-feature-values Bickham Script {
@swash {
fancy: 1; /* Sets swsh to 1 */
}
}
h1 {
font-family: "Bickham Script";
font-variant-alternates: swash(fancy);
}
ornaments()
Ornaments (equivalent to the ornm
feature tag) are glyphs used purely for aesthetic purposes. Unlike stylistic alternates, ornaments don’t have a semantic meaning and aren’t linked to any character. Per OpenType spec, we can replace the bullet character with an ornament or replace specific “lower ASCII” characters.
@font-feature-values Anggrelli {
@ornaments {
a-fleuron: 1; /* Sets ornm to 1 */
}
}
h1 {
font-family: "Anggrelli";
font-variant-alternates: ornaments(a-fleuron);
}
annotation()
Annotations (equivalent to the nalt
feature tag) refer to the different ways numbers can be displayed, usually as glyphs placed in open or solid circles, squares, parentheses, diamonds, or rounded boxes. This feature replaces the default number form with its annotation versions.
@font-feature-values Gothic A1 {
@annotation {
a-fleuron: 6; /* Sets nalt to 6 */
}
}
h1 {
font-family: "Gothic A1";
font-variant-alternates: annotation(a-fleuron);
}
Specification
The font-variant-alternates
property is defined in the CSS Fonts Module Level 4 specification, which is currently in Editor’s Draft.
Browser support
Both the @font-feature-values
and the font-variant-alternates
are supported on all browsers.
More information
- Wakamai Fondue (Roel Nieskens)
- The Complete CSS Demo for OpenType Features (Sparanoid)
- OpenType Features (Preuss Type)