Upcoming changes to the CSS you need for variable fonts
Two weeks ago I was invited to Berlin for a CSS Working Group three-day meeting. One afternoon was dedicated to resolving issues with the CSS Text and Font modules. Two resolutions in particular will affect the CSS we need to work with variable fonts.
1. Font weights
According to the current CSS Fonts Level 4 specification, this is the basic way to use any webfont (variable or static):
@font-face {
font-family: Gentium;
src: url(gentium.woff);
}
What this rule doesn’t make obvious is the effect absent property descriptors have. Implicit in this rule are font-weight
, font-stretch
and font-style
descriptors which, even when not specified, are still set. This means the preceding simple rule – at the time of writing – is actually the same as:
@font-face {
font-family: Gentium;
src: url(gentium.woff);
font-stretch: normal;
font-style: normal;
font-weight: normal;
}
This is important because font-weight:normal
is an alias for font-weight:400
, and when you include a font-weight
descriptor in an @font-face
rule, you are telling the browser that the font corresponds to that weight, and that weight only. By omitting the font-weight
descriptor, what you are actually instructing the browser to do is ‘clamp’ the font to the default weight of 400. This is the case whether or not your font has a weight axis variation.
To make use of the weight axis, and for the font-weight
properties to work as you might expect, you need to add a weight range to the font-weight
descriptor:
@font-face {
font-family: Gentium;
src: url(gentium.woff);
font-weight: 1 999;
}
The font weight range allows the variable font to be displayed at any weight from 1 to 999. The same is true of the other property descriptors: font-style
is clamped to an upright position – to make use of a slant axis you would need to include a range of angles. For font-stretch
you would need a range of absolute widths to make use of a width axis. Ideally you would specify ranges which match the extremes of the axes in the font.
@font-face {
font-family: Gentium;
src: url(gentium.woff);
font-weight: 1 999;
font-style: oblique -90 90;
font-stretch: 50% 200%;
}
The forthcoming change to the specification is subtle but important. It will change the default value of font-weight
from normal
to auto
, thus enabling the full range of weights available in the variable font, and defaulting to normal
for static fonts. The same applies to other property descriptors. This means that – in the future – if you omit the descriptors, the variable fonts will still function across the full range of their axes. Be aware that if you do include a single value descriptor such as font-weight:300
a variable font will still be clamped to that value.
The CSS WG resolution on this change, and accompanying minutes from the CSS WG meeting, is documented in this Github issue.
2. Requiring variable fonts
Variable fonts are not a new font format, they are OpenType fonts that contain additional tables of data which describe variations possible within the font. This means variable fonts are still .ttf
or .otf
files, and so can be made into WOFF or WOFF2 formats. The upshot is that the font pointed to in the previous @font-face
rule may or may not be a variable font, but it could be important to know either way in order that styles requiring variable fonts are applied, and fallback fonts are provided for browsers which don’t support font variations.
Currently the way that you could provide a fallback static font is by specifying the variable font through a format()
hint like this:
@font-face {
font-family: 'Gentium';
src: url(gentium-var.woff2) format('woff2-variations'),
url(gentium-static.woff2) format('woff2');
}
However the list of potential format strings is growing fast and could in future contain other kinds of font features, such as colour fonts. With an eye on the future, the CSS Working Group recently resolved to change the syntax of the format()
hint separate out the font features from the file type:
@font-face {
font-family: 'Gentium';
src: url(gentium-var.woff2) format('woff2' supports variations),
url(gentium-static.woff2) format('woff2');
}
A problem with this new syntax is that currently it causes the entire src
descriptor to be invalid and thus the whole @font-face
rule is ignored. To address this the CSS WG also resolved a change in the way the src
descriptor should be handled: browsers should parse the value of src
throwing out invalid parts in the manner of media queries rather than selectors. In other words they should split on the commas and throw out the pieces they don’t understand, not the whole src
descriptor.
Once the new syntax is implemented, you could still provide fallback fonts without breaking older browsers by repeating the src
like this:
@font-face {
font-family: 'Gentium';
src: url(gentium-static.woff2) format('woff2'),
url(gentium-static.woff) format('woff');
src: url(gentium-var.woff2) format('woff2' supports variations);
}
The CSS WG resolution on this change, and accompanying minutes from the CSS WG meeting, is documented in this Github issue.
Variable fonts are a high priority for browser makers at the moment, so these changes should make it into the CSS Fonts Module Level 4 specification (thanks to Apples’s Myles Maxfield) and major browser implementations over the next few months.