Clagnut

Menu

Upcoming changes to the CSS you need for variable fonts

§ Web standards · Typography · CSS techniques

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.

Ampersand

To get the full low-down on variable fonts - and a lot more besides - join me and experts from around the world at Ampersand to get the full picture of what web typography can be today. The day before the conference I’ll also be running a responsive web typography workshop.