How to hack beautiful flourishes into your font
How to hack beautiful flourishes into your font

I've recently been doing some work on making Superhuman the most beautiful email experience in the world.

One of the features we want is automatic "smart quotes".

Instead of bland vertical quotes, we'd use fun, curvy quotes to make the text feel more alive:

I'd known for a while that OpenType was capable of processing during font rendering. So I set myself the challenge of implementing smart quotes in the font file itself.

To cut a long-story short: it works, and it's easy to modify an existing font to support it!

1. font-feature-settings

The first trick to getting fancy font features working on the web is to set up your font-feature-settings CSS properties (or -moz-font-feature-settings for Firefox):

body {
  font-feature-settings: "kern" 1, "dlig" 1;
}

NB: This is supported up-prefixed by Chrome 50, IE 9, Safari 9.1, and Firefox 34. Chrome enables "kern" by default, Safari enables both "kern" and "dlig" by default.

Your font-feature-settings property will be a list of quoted four-letter OpenType features, followed by a number for their value.

The most essential feature to enable is "kern", which enables proper kerning:

Kerning corrects letter spacing

It's also nice to enable "liga" and "dlig" which control the use of ligatures:

Ligatures correct for specific combinations of adjacent letters

Look at the following image. Notice how the ugly space between the nw of Fanwood is tightened, and how the messy fl is replaced by a ligature.

2. Smart quotes

The second trick is to actually implement curly quotes.

Under the hood, each OpenType feature is a set of pattern matches. When a certain sequence of glyphs occurs, you can substitute in a new glyph, or change its position.

The OpenType Cookbook is a good reference for the syntax, which is supported by most font editing tools and processed by the ADFKO.

The patterns are very simple, yet you can use a few techniques to implement surprisingly complicated substitutions:

  1. You can specify an ignore rule to skip a rule.
  2. You can define character classes to group characters together.
  3. You can group rules into lookups, using only one rule from each lookup.

Exercise for the reader: I think this makes an OpenType font a finite-state machine, anyone fancy implementing arbitrary regexes?

Starting small, we can create a simple rule to replace exactly two hyphens (--) by an em-dash ( — ):

# ignore two hyphens followed by a third hyphen
ignore sub hyphen' hyphen' hyphen;

# and ignore two hyphens preceded by a hyphen
ignore sub hyphen hyphen' hyphen';

# replace all remaining hyphens by em-dashes
sub hyphen' hyphen' by emdash;

To implement smart-quotes we need to be able to tell if a quote is at the start of a line.

We can approximate this by defining the character class @All which contains all the glyphs in the font. We can then use @All to catch any quotes that happen after a character. Quotes that don't happen after any character are at the start of a line.

#smart-quotes
# quotes surrounded by spaces, just leave aloneignore sub space quotedbl' space;

# quotes after numbers, assume are primes, and leave alone 
ignore sub [
  one two three four five six seven eight nine zero
] quotedbl';

# quotes after opening characters are open-quotes
sub [space
     equal
     less
     parenleft parenleft.u
     bracketleft bracketleft.u
     braceleft braceleft.u
     guillemotleft guillemotleft.u
     guilsinglleft guilsinglleft.u
     quotedblleft quoteleft quotesingle quotedbl
] quotedbl' @All by quotedblleft;

# other quotes in the middle of the line are closing quotes
sub @All quotedbl' by quotedblright;

# quotes at the start of the line are opening
sub quotedbl' @All by quotedblleft;

Because there was no pre-defined OpenType feature name for smart quotes, I added it to the font as "ss01" or Stylistic Set 1. This is the result:

3. Hanging punctuation

Finally, inspired by Typeset, I wanted to see if I could also implement hanging punctuation. This gives the left-margin of a paragraph a strong vertical line by having punctuation marks hang to the left.

Once I had the substitution rules and the character classes set up for the smart quotes, this turned out to be simple:

# feature "opbd"
ignore pos @All quotedblleft';
pos quotedblleft' <-421 0 -421 0>;

ignore pos @All quoteleft';
pos quoteleft' <-228 0 -228 0>;

The positioning rules move the left and right of the glyph independently. The number 421 comes from looking at the glyph for a curvy left quote and taking its width including some spacing. I only needed to look at the curly left-quote, because the "opbd" feature is defined after "ss01" and so all the plain quotes have already been replaced at this point.

This technique only works for punctuation on the left, but as most text on-screen is set with a ragged right margin, we don't need punctuation that hangs out to the right.

More work could be done — for example, Typeset moves "Y"s, "V"s and "W"s out a little too — but this serves as a proof of concept.

Conclusion

Implementing smart-quotes in your font is totally doable.

It's not as good as using the correct glyphs in the first place, but it's on-par with doing it in Javascript. And it's a lot more convenient: there's no code to run.

You can download my hacked version of Fanwood Text from GitHub, or preview it here.

I used Glyphs to open the existing Fanwood font and add new features. If you use a different app the UI may be slightly different, though I'm sure you can re-use the syntax.

That's all for now — please recommend and share if you enjoyed this. And don't forget to follow our publication for more updates!