Google Font Features

| fonts | google | go | yakshaving

tl;dr Google Fonts doesn’t supply fonts with OpenType features (such as old-style figures, or small-caps), but you can build and host the fonts yourself to support everything you need.

I recently posted a article which contained lots of numbers. While I was proofreading the article, I didn’t quite liked how the numbers looked, sometime the digits were below the baseline, for example:

Oldstyle figures

Where I would have expected the top and bottom of each digit to be aligned:

Lining figures

This made me flashback to all the typography I learnt when working with LaTeX. These two styles of figures are called old-style, and lining (or sometimes lowercase and uppercase numbers). The theory is that old-style numbers flow better when mixed with text. Recall, letters like q, j and p, all drop below the baseline, which makes the text nicer to read:

Example with characters below the baseline

However, my article had many numbers on the page, sometimes within tables, where old-style just made the numbers look odd. I looked for a way to force the lining style throughout. I quickly found the CSS styling:

body {
           font-variant-numeric: lining-nums; 
  -webkit-font-feature-settings: "lnum" on;
     -moz-font-feature-settings: "lnum" on;
      -ms-font-feature-settings: "lnum" on;
          font-feature-settings: "lnum" on;
}

Sadly when I applied this to my site, it did nothing. I wondered if perhaps the font did not support lining figures. A quick search led me to Stack Overflow that implied both the font I was using, Raleway, and Google Fonts (which hosted the font) did in fact support lining.

So I went deeper down the rabbit hole to figure out what was going wrong. I wanted to confirm for myself that the font supported lining figures. I searched for a while for a simple CLI that would inspect the WOFF/TTF files and tell me what they contained. Sadly, the best I could find was FontForge, a GUI. That worked, and confirmed the fonts being served by Google did not contain the lining feature, or in fact any feature other than basic ligatures.

Later I found this GitHub issue which confirmed all features were stripped from the font. So I sought out a way to rebuild the Google font to keep the lining figures.

Before that, I started to shave another yak, and decided to create a CLI tool that would easily display the font features. I came across a Go library, SFNT that can parse OpenType fonts. Sadly it didn’t implement the parsing of the features. A few hours later, I read the OpenType spec and sent them a pull request to add this functionality. Now I can easily confirm from the command line what features are supported.

$ font features raleway-v12-latin-ext_latin-regular.woff
Glyph Substitution Table (GSUB):
	Script "latn" (Latin):
		Default Language:
			Feature "liga" (Standard Ligatures)

I decided to play around with Google Font API, and then eventually the unoffical (but awesome) google-webfonts-helper (a hassle-free way to self-host Google Fonts). However, no combination of options would make the font contain the lining figures.

Since the Google Fonts are open source, I downloaded the source TTF of the font, and double-checked it did indeed contain the feature:

$ font features Raleway-Regular.ttf 
Glyph Substitution Table (GSUB):
  Script "latn" (Latin):
    Default Language:
      Feature "aalt" (Access All Alternates)
      Feature "dlig" (Discretionary Ligatures)
      Feature "liga" (Standard Ligatures)
      Feature "lnum" (Lining Figures)
      Feature "onum" (Oldstyle Figures)
      Feature "salt" (Stylistic Alternates)
      Feature "smcp" (Small Capitals)
      Feature "ss01" (Stylistic Set 1)
      Feature "ss02" (Stylistic Set 2)

So my next idea was to take the original Raleway-Regular.ttf and convert it to WOFF and WOFF2, and strip out the bits I don’t need. Just how Google Fonts does, to ensure the resulting files are lean and performant.

I couldn’t find the pipeline Google Fonts uses to process the files, so I instead took it upon myself to figure this out. I started by using pyftsubset (part of FontTools) to remove unneeded character sets, features, and other parts from the original TTF file.

$ pip install fonttools
$ pyftsubset Raleway-Regular.ttf --layout-features='*' --unicodes="U+0000-00FF, U+0100-024F, U+0131, U+0152-0153, U+02DA, U+02DC, U+02BB-02BC, U+02C6, U+0259, U+0370-03FF, U+1E00-1EFF, U+2000-206F, U+2070-209F, U+2074, U+20A0-20CF, U+2122, U+2150-218F, U+2200-22FF, U+2C60-2C7F, U+A720-A7FF" --output-file=Raleway-Regular.subset.ttf

Now I had a TTF file with all the features, but only the subset of characters I use on my site. Next I needed to convert this this file to all the recommended font formats, so my site would look nice in IE, Chrome, Android and iOS. The resulting CSS would look like this:

@font-face {
  font-family: 'Raleway';
  src: url('raleway-regular.subset.eot');                           /* IE9 Compat Modes */
  src: local('Raleway'), local('Raleway-Regular'),
       url('raleway-regular.subset.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
       url('raleway-regular.subset.woff2') format('woff2'),    /* Super Modern Browsers */
       url('raleway-regular.subset.woff') format('woff'),     /* Pretty Modern Browsers */
       url('raleway-regular.subset.ttf') format('truetype'),    /* Safari, Android, iOS */
       url('raleway-regular.subset.svg#ralewayregular') format('svg');    /* Legacy iOS */
  font-style: normal;
  font-weight: 400;
}

I again tried to use pyftsubset to save the files in the required formats. This worked well for TTF, WOFF, and WOFF2. But didn’t support EOT or SVG fonts:

$ pip install zopfli
$ pip install brotli
$ pyftsubset ... --flavor=woff --with-zopfli --output-file=Raleway-Regular.subset.woff
$ pyftsubset ... --flavor=woff2 --output-file=Raleway-Regular.subset.woff2

So instead I searched for a all-in-one solution to converting fonts. I found numerous websites that offered to do it, the one I settled on was fontsquirrel.com. Here I used the expert feature, to control exactly what was in the font, and to produce compressed versions in all file formats. I originally tried to use the subsetting feature on fontsquirrel, but I couldn’t get it to maintain all the features I needed, so I used pyftsubset locally instead.

After fontsquirrel.com produced the fonts, I checked it contained the features, and compared the resulting file sizes:

$ ls -ltr

# Google Fonts
 96K  raleway-v12-latin-ext_latin-regular.ttf
 40K  raleway-v12-latin-ext_latin-regular.woff
 31K  raleway-v12-latin-ext_latin-regular.woff2

# My versions
140K raleway-regular.subset-webfont.ttf
 61K raleway-regular.subset-webfont.woff
 46K raleway-regular.subset-webfont.woff2

$ font features raleway-regular.subset-webfont.woff
Glyph Substitution Table (GSUB):
  Script "latn" (Latin):
    Default Language:
      Feature "aalt" (Access All Alternates)
      Feature "dlig" (Discretionary Ligatures)
      Feature "liga" (Standard Ligatures)
      Feature "lnum" (Lining Figures)
      Feature "onum" (Oldstyle Figures)
      Feature "salt" (Stylistic Alternates)
      Feature "smcp" (Small Capitals)
      Feature "ss01" (Stylistic Set 1)
      Feature "ss02" (Stylistic Set 2)

The file size didn’t vary too much, and thus it was a simple matter of uploading the fonts to my blog, and updating the CSS.

1234567890  vs  1234567890