If you do a great job designing your typography system, most will not notice. At least not in any obvious or specifiable way. This is because good typography is invisible. It is easy to make safe or “boring” choices in typography and rarely go wrong; the margin for error if you stay on the conventional path is fairly small. But what about overengineering a typography system? How far can you push it for an extra fraction of readability? Is it worth it?

The Case for Readability

Humanist fonts are generally considered the most readable for long-form text because:

Geometric Humanist fonts offer:

Code Monospace fonts prioritize:

Rounded Sans Serif fonts provide:

The Readability Rankings

I’ve created a detailed scoring system based on four key factors that affect digital readability at 16px:

  1. Letter Distinction - How easily distinguishable individual characters are
  2. Eye Strain Prevention - How well the font prevents fatigue during extended reading
  3. Screen Rendering - How clearly the font renders on digital displays
  4. Reading Flow - How naturally text flows during continuous reading

The overall rankings from most to least readable for long-form digital content at 16px are:

  1. Humanist (8.8/10)
  1. Geometric Humanist (8.5/10)
  1. Rounded Sans Serif (7.8/10)

The Science Behind the Scores

The most rigorous research on digital font readability comes from a few key sources:

  1. Microsoft’s Cleartype studies (particularly their work on Verdana and Georgia)
  2. Legibility studies like those from the MIT AgeLab
  3. Google’s font readability research that informed their font “Roboto”

However, I should note that many of these scores would benefit from more empirical backing - they’re informed by typographic principles but aren’t strictly scientific measurements.

For web rendering specifically, here are some evidence-based techniques to improve humanist font crispness:​​​​​​​​​​​​​​​​

Key research-backed points about the scoring:

  1. Letter Distinction:
  1. Eye Strain:
  1. Screen Rendering:
  1. Reading Flow:

Font Subsetting Strategy for Inter

I optimized Inter for web use through strategic subsetting and progressive loading, focusing on essential weights and characters while maintaining excellent typography.

Weight Selection

I chose weights 400-600 to cover core use cases:

This range provides adequate typographic contrast while avoiding the bandwidth cost of full weight coverage. The 400-600 range is particularly suitable for screen rendering, as extreme weights can suffer from inconsistent rasterization across platforms.

Character Set Division

Split into two subsets for efficient loading:

  1. Core Package (24.1KB):
pyftsubset "Inter.ttf" \
  --unicodes="U+0020-007F" \
  --layout-features="kern,calt" \
  --flavor="woff2" \
  --output-file="inter-core.woff2"

Covers ASCII range (U+0020-007F) - essential Latin characters, numbers, and basic punctuation.

  1. Supplemental Package (15.5KB):
pyftsubset "Inter.ttf" \
  --unicodes="U+00A0-00FF" \
  --layout-features="kern,calt" \
  --flavor="woff2" \
  --output-file="inter-supplement.woff2"

Includes extended Latin characters and special symbols.

Implementation

/* Core Latin - Load Immediately */
@font-face {
  font-family: "Inter";
  src: url("inter-core.woff2") format("woff2");
  font-weight: 400 600;
  font-display: swap;
  unicode-range: U+0020-007F;
}

/* Supplemental Characters - Load Later */
@font-face {
  font-family: "Inter";
  src: url("inter-supplement.woff2") format("woff2");
  font-weight: 400 600;
  font-display: optional;
  unicode-range: U+00A0-00FF;
}

Technical Rationale

Future Optimization Paths

The result balances performance with typographic quality, delivering excellent screen rendering while maintaining reasonable load times. Total payload (18.4KB) remains well within performance budgets for modern web applications.​​​​​​​​​​​​​​​​

Here’s my recommended approach for header hierarchy, assuming a 16px base size for body text:

Type Scale and Header Structure

After extensive testing across devices, I’ve settled on a subtle and readable type scale for long-form content. With the main header (h1) reserved for site titling, here’s how I structure content headers:

@function rem($pixels) {
  @return ($pixels / 16) * 1rem;
}

/* Base Typography */
$text-base: rem(16);
$text-sm: rem(14);

/* Header Scale */
$text-h1: rem(21);
$text-h2: rem(18);
$text-h3: rem(16);

I chose these specific values because they provide enough distinction between levels while maintaining harmony. The scale is subtle enough to avoid the common problem of headers appearing too large and dominating the content.

For weights, I recommend:

h2,
h3 {
  font-weight: 600;
} /* bold for all headers */

A key detail I’ve found important: add slightly more line height to h2 and h3 to accommodate possible wrapping:

/* Margin & Padding */
$spacing-xs: rem(2);
$spacing-sm: rem(12);
$spacing-md: rem(18);
$spacing-lg: rem(24);
$spacing-xl: rem(32);

h2,
h3 {
  line-height: 1.3;
  margin-bottom: $spacing-sm;
}

This structure works particularly well for long-form content because:

You’ll notice I avoided multipliers (like 1.25x) in favor of specific values. This gives us more control over the exact sizes while maintaining clean numbers that scale well. The 28px maximum for h2 keeps content headers from competing with the site title while still providing adequate emphasis.​​​​​​​​​​​​​​​​