Class Based Contextual Positioning in MonoSpaced Fonts

Increasing readability one x-axis shift at a time

Andreas Larsen


This article is part 3 of a series I’m writing about Monoid. I recommend you start by reading part 1 + part 2 if you haven’t already. I’m @larsenwork on Medium, Twitter and GitHub.

The Problem

Monospaced fonts consists of letters that aren’t “naturally” equal width — e.g. w and i.

This results in unequal spacing between letters which decreases the readability.

Top to bottom: Monoid, Pragmata Pro, Fira Mono and Source Code Pro

The Conventional Solution

What monospaced fonts do is to either ignore it (uncommon) or to make narrow letters wider and wide letters narrower to even out the difference.

The wide letters get squeezed and the narrow letters get slab serifs. The problem with adding slab is it reduces distinguishability discussed in part 2.

Notice how — in the example above — the l and I in Pragmata Pro looks fairly similar. The same can be said for 1 and I in Fira Mono and Source Code Pro.

There is also a limit as to how much you can squeeze letters such as w and m.

Class Based Contextual Positioning

What I’m trying to do is slightly different but not entirely new.

Class based adjustment in fonts is standard in “normal” fonts where kerning is almost always added based on letter classes — i.e. consider the class @A containing e.g. À, Á, Â, Ã, Ä and Å. Then you’d almost allways want this to happen: When @A comes before V then reduce letter spacing by x points.

The show-stopping problem for this approach in Monospaced fonts is that kerning also removes the monospace. In the example above every letter after V will be shifted to the left.

What I’m doing instead is changing the positioning of the letters leaving the total width and thus the positioning of every following letter unchanged.

This may sound a bit tricky but it really isn’t. Consider “Miami”. If you write that with a monospaced font it will look a bit like Mi ami instead of Miami. You can describe the letters like this:

Miami = wide+narrow+medium+wide+narrow

To fix Miami you want to move the first narrow letter to the right and the medium letter to the left. You’ll hopefully agree with me that the spacing in the second screenshot is better and it’s easier to read.

Notice how the overall width is unchanged — it’s still monospaced.

How it’s (currently) done:


Classes are created based on letter width.


You define all sorts of problematic context.


If you’ve read part 1 you’ll know that 1px = 128pt at 15px font size because Monoid has an EM size of 1920 (1920 / 15 = 128). Since I’d like to stick to the grid I get the following two options (for regular).

Class Based Contextual Positioning

Please forgive me how messy the code currently is — it’s been a trail and error process for me to figure out precisely how the looping in feature files works. I’ll soon take a more systematic approach.


You can see the result in the header image but I’d recommend you visit using most modern browsers and turn ligatures on/off to see the difference.

Please note that you can’t turn the ligatures off in Safari and/or your iOS device. It’s slightly ironic that a company claiming to care about typography has a browser that doesn’t even support established opentype features supported by everyone else. /rant


You can argue that the horizontal rhythm (the monospaced-ness) is affected too much but I obviously don’t think it’s the case. Or put more correctly: I find the gain in readability due to improved spacing to outweigh the slightly less pronounced horizontal rhythm.

Some editors doesn’t yet support the opentype feature “calt” required to make this work.


If you have any comments on this or find any bugs then I’d like to hear them here:

I don’t know what I’ll write next but there are definitely more articles comming in this series.



Andreas Larsen

Jack of all trades — master of some. Design+Code+Type+DIY. Meetup organizer.