Disambiguation in technical interfaces

The gist: Before using a mono typeface to improve the clarity of single line non-lexical strings, check available character alternatives in your base typeface. This can offer similar benefit, without needing to balance a differently-proportioned typeface.

Settings
Project/Builds/1i0Ol84a
Build #4251

Deployed to production successfully

2 min ago

Build Information

Duration3m 42s
Build ID1i0Ol84a-5e6f-7a8b-9c0d-e1f2a3b4c5d6
Triggered byBrett Jones
Commit1I0ol8a2
Branchfeat/user-authentication-v2
Imagesha256:1i0Ol84d5e6f7a8b9c0d1e2f

Deployment Details

Deploy IDdpl_8x9y0zIlO0i1a2b3c4d5e
Domainapp.example.io
Regionus-east-1
StatusActive
Instancei-O0l1i8a4b3c2d1e

Metadata

FrameworkNext.js 14.2.1
Node Versionv20.11.O
Build Commandnpm run build
Cache KeyIl0O-8a9b-1c2d-3e4f

I sometimes see interfaces take the following approach to text styling:

  1. Use a base sans-serif system typeface
  2. Present non-lexical strings (such as commit SHAs or UUIDs) in monospace
Example UI
ACME
/
Project
/
1i0Ol84

This works. Mono typefaces excel at disambiguating characters that can be difficult to distinguish, such as “ilIoO01. Plus it can add a nice, technical flair to the visual design.

But there are drawbacks. Most intuitively, the width of content set in a mono typeface scales linearly per character, compared to proportional sans-serif typefaces.

Example UI
ACME
/
Project
/
des-420-Imalongfeaturebranchname

But more subtly: the greater the ratio of mono text in a sans-serif interface, the more the differences in optical qualities between the two begin to clash and feel unbalanced.

While both examples use identifical styles, the shorter commit SHA doesn’t feel as unbalanced with the surrounding sans-serif interface as longer git branch does.

You could try tweaking the size of monospace fonts to optically balance them.

Example UI
ACME
/
Project
/
des-420-Imalongfeaturebranchname
.mono-correction {
font-size: 0.95em;
}

But for single line contexts, there are alternatives.

Some typefaces like Geist from Vercel have type design choices which blend technical character disambiguation styles similar to mono typefaces into the default character set.

But for even more control, many typefaces include alternative characters that can be activated, either for stylistic flair or where greater precisision is desired.

In CSS, this is achived with font-feature-settings. This allows you to enable specific opentype feature tags specified by the typeface to render alternative characters available in the font.

Example UI
ACME
/
Project
/
des-420-Imalongfeaturebranchname
.font-precise {
font-feature-settings: 'ss02' 1;
}

Compare with the monospace version, you get some of the legibility improvements provided by monospace, while maintaining balance with the rest of the interface:

Comparison
ACME
/
Project
/
des-420-Imalongfeaturebranchname

ACME
/
Project
/
des-420-Imalongfeaturebranchname
Disambiguation:

Note the specific opentype feature tags vary between font families. Many have great documentation, here are a couple of opengraph feature tags available from Inter:

PropertyDefinition
ss02Disambiguation set
cv05Lower-case L with tail
cv08Upper-case i with serif
zeroSlashed zero

There’s many other features, a personal favourite of mine in the Inter typeface is cv11, which replaces the default “a” glyph with a single story “a”.

Applying with CSS

Depending on your project, you might choose one of two approaches for implementing:

  • Globally: All text will render with the disambiguated character set. This might make sense if your product is highly technical. Great choice for marketing sites.
  • Specifically: Add a utility class that activates disambiguation selectively for non-lexical strings, offering the benefit of monospace typefaces without the optical imbalance and per-character width scaling.

Applying globally

Globally with regular CSS

Use the font-feature-settings rule and activate the desired alternatives.

style.css
body {
font-feature-settings: 'ss02' 1;
}

Globally with Tailwind 4

Use the font-*--font-feature-settings custom property in your theme configuration to activate alternative character variants for the corresponding Tailwind font family utility class, such as font-sans.

global.css
@theme {
--font-sans: Inter, 'sans-serif';
--font-sans--font-feature-settings: 'ss02' 1;
}

With a utility class

Regular CSS utility class

Create a class with the corresponding font-feature-settings activated.

styles.css
@layer utilities {
.font-precise {
font-feature-settings: 'ss02' 1;
}
}

Tailwind utility class

Similar to above, but use the Tailwind @utility directive.

global.css
@utility font-precise {
font-feature-settings: 'ss02' 1;
}

Conclusion

Your mileage (and preference) may vary, depending on the context of the product and the ratio of content rendered in monospace in your user interface. But it’s nice that so many of the typefaces we use day-to-day have these options, that can be enabled both for accessibility (and stylistic) flair!

Regardless, monospace still has its place. Particularly for multi-line code blocks where alignment between rows is desired. But for other contexts where you desire greater precision in a UI, check what alternatives your base typeface has, and in many cases a few small tweaks to your standard typeface might be all you need.

Style
Pros
Cons
System font
  • Proportal letter scaling
  • Optimised for ui and prose
  • Some characters in non-lexical strings can be hard to distinguish

Monospace
  • Clear character distinction
  • Column alignment between rows
  • Line length scales with each character
  • Can appear disproportional next to sans serif fonts

Disambiguation alternatives
  • Optimized for UI and prose
  • Improved
  • Larger font size bundle
  • Unsuitable for multi-line contexts where column alignment is desired

Improved precision with technical content is only one use-case of alternative typeface characters. Stylistic alternatives available through opentype feature tags open up opportunities for subtle distinction and differentiation too!

Footnotes

  1. On a meta note, I applied Inter’s disambiguation stylistic alternative here specifically to distinctly render those characters.