← All Posts

Type Scales: How I Chose 13 Steps and Why the Ratio Matters

Robert Bringhurst’s The Elements of Typographic Style established that harmonious type relationships follow the same mathematical ratios found in music: the perfect fourth (1.333), the perfect fifth (1.5), and the golden ratio (1.618). I started with a perfect fourth and ended with a custom progression that no standard ratio produces — because my content structure demanded specific steps between body text and display headlines.1

TL;DR

A type scale generates a hierarchy of font sizes from a base size and a mathematical ratio. After building the typography system for blakecrosley.com — 13 steps from 0.75rem (12px) to 5rem (80px), using system fonts exclusively — I’ve learned that the ratio matters less than the steps between body text and H1. My scale uses a roughly 1.18 progression between adjacent steps but makes deliberate jumps (from 3.875rem to 5rem) where the content structure requires visual separation. The interactive comparison below shows the difference between strict ratios and content-driven adjustments.


My Type Scale: 13 Steps

Here is the actual scale from my site’s critical.css:

:root {
  --font-size-xs:      0.75rem;   /* 12px — metadata, timestamps */
  --font-size-sm:      0.875rem;  /* 14px — captions, fine print */
  --font-size-base:    1rem;      /* 16px — body text, default */
  --font-size-lg:      1.125rem;  /* 18px — lead paragraphs */
  --font-size-xl:      1.3125rem; /* 21px — large body, section intro */
  --font-size-2xl:     1.5625rem; /* 25px — H4, card titles */
  --font-size-3xl:     1.875rem;  /* 30px — H3 */
  --font-size-4xl:     2.25rem;   /* 36px — H2 */
  --font-size-5xl:     2.7rem;    /* 43.2px — H1 */
  --font-size-6xl:     3.25rem;   /* 52px — large H1 */
  --font-size-7xl:     3.875rem;  /* 62px — page title */
  --font-size-display: 5rem;      /* 80px — hero headline */
}

The progression between adjacent steps is not a strict mathematical ratio. The steps from xs to xl follow roughly 1.17-1.18x. The steps from 5xl to display jump more aggressively (1.20-1.29x) because the hero headline needs visual separation from page-level headings.2

Why Not a Strict Ratio?

A strict major third (1.25) from a 16px base produces these steps: 16, 20, 25, 31.25, 39.06, 48.83, 61.04. The jump from body (16px) to H3 (31.25px) is nearly 2x — too dramatic for content-heavy pages where H3 appears frequently. My scale compresses the middle range (18, 21, 25, 30, 36) to keep headings proportional to body text while expanding the top range (43, 52, 62, 80) for display typography.

The content structure drove the scale, not the mathematics. I tested every step against real blog post content and adjusted sizes where the squint test failed.3


Why System Fonts

My font stack:

:root {
  --font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text",
                 "SF Pro Display", "Helvetica Neue", Arial, sans-serif;
}

The Performance Argument

System fonts load in zero milliseconds. No network requests, no FOIT (Flash of Invisible Text), no FOUT (Flash of Unstyled Text). The choice contributes to my 100/100 Lighthouse performance score.

Custom web fonts typically add 100-300ms to First Contentful Paint due to font file downloads and browser rendering decisions. Google Fonts loads from a CDN (one DNS lookup + one HTTP request minimum). Self-hosted fonts eliminate the DNS lookup but still require the download. System fonts eliminate every component of font-loading latency.4

The Design Argument

System fonts match the platform. On macOS, my site renders in SF Pro — the same typeface used by macOS system UI, Apple Mail, and Safari chrome. The visual continuity between the operating system and the website feels native rather than branded.

Linear, Vercel, and Raycast use the same approach. The pattern emerged from my 16 product design studies: products that prioritize content readability over brand expression tend to use system fonts.

When Custom Fonts Are Worth It

Custom fonts serve marketing pages, brand identity, and display typography where the typeface IS the design. My site is content-first (blog posts, project descriptions), where the typography should be transparent — readers should process the content, not notice the font.


The Weight System

Four weights handle all hierarchy needs:

:root {
  --font-weight-normal:   400;  /* Body text */
  --font-weight-medium:   500;  /* Navigation, labels */
  --font-weight-semibold: 600;  /* Subheadings, emphasis */
  --font-weight-bold:     700;  /* Headlines, primary actions */
}

Combined with the 13 size steps and four opacity tiers, I have 208 potential combinations (13 sizes × 4 weights × 4 opacities). In practice, I use roughly 15 combinations consistently. The system provides flexibility without requiring a decision at every text instance — most text uses base size, normal weight, primary opacity.5


Responsive Typography

The Problem With Single Ratios

A type scale designed for desktop produces oversized headings on mobile. My display size at 80px fills a 1440px viewport beautifully but overwhelms a 375px phone screen. Rather than scaling the entire system with viewport units, I override specific breakpoints:

@media (max-width: 1024px) {
  .hero__title { font-size: var(--font-size-6xl); }  /* 52px */
}

@media (max-width: 768px) {
  .hero__title { font-size: var(--font-size-3xl); }  /* 30px */
}

The body text stays at 16px across all viewports — body text does not need to scale because 16px remains readable on every modern screen. Only display and heading sizes reduce on smaller viewports. The approach is simpler than fluid typography (clamp()) and produces predictable results at known breakpoints.6

Letter-Spacing at Display Sizes

Large type needs tighter tracking. At 80px, the default letter-spacing produces visible gaps between characters:

.hero__title {
  font-size: var(--font-size-display);
  font-weight: var(--font-weight-bold);
  letter-spacing: -0.03em;
  line-height: 1.05;
}

The -0.03em letter-spacing and 1.05 line-height produce tight, impactful headlines. Body text at 16px uses the default letter-spacing with a generous 1.7 line-height for readability. The contrast between tight headlines and airy body text creates visual rhythm without decoration.7


Testing Typography

The Squint Test

Blur your eyes or step back from the screen. The heading hierarchy should remain visually distinct at every level. If H3 and H4 blend together, the ratio is too small for the chosen font.

I applied the squint test to my scale and identified that --font-size-xl (21px) and --font-size-2xl (25px) blurred together at first. Adding a weight difference (xl uses normal 400, 2xl uses semibold 600) resolved the distinction without changing sizes. Weight provides hierarchy independently of size.8

The Content Test

Populate every heading level with real content. Placeholder text masks hierarchy problems because “Lorem Ipsum” lacks the visual weight variation of real language. I test every scale adjustment against my longest blog post (Hamming error correction, 2000+ words with H2, H3, H4, code blocks, tables, and footnotes). If the scale works for the most complex content, it works for everything.


Key Takeaways

For designers: - Start with a base size of 16px and test ratios between 1.15 and 1.25 against real content; strict mathematical ratios often require content-driven adjustments at the extremes - Use the squint test and content test before finalizing; visual distinction at every heading level matters more than mathematical purity

For developers: - Define type scales as CSS custom properties at the :root level; reference var(--font-size-*) throughout the codebase to prevent arbitrary font sizes from accumulating — CSS custom properties work natively in every browser without a build step - Consider system fonts before custom web fonts; the 100-300ms font-loading savings compounds across every page load, and system fonts provide platform-native readability - Use breakpoint overrides for display sizes rather than fluid typography if predictable results at known widths matter more than smooth interpolation


References


  1. Bringhurst, Robert, The Elements of Typographic Style, Hartley & Marks, 2004. Foundation text on proportional typography. 

  2. Author’s type scale from critical.css. 13 steps from 0.75rem to 5rem. Custom progression with compressed middle range and expanded display range. 

  3. Author’s scale testing. Each step tested against real content (longest post: 2000+ words). Middle range compressed after squint test revealed insufficient distinction. 

  4. Author’s performance measurement. System fonts contribute to 100/100 Lighthouse performance score. Zero font-loading latency documented in performance audit. 

  5. Author’s typography token system. 13 sizes, 4 weights, 4 opacity tiers = 208 combinations. ~15 used consistently in production. 

  6. Jehl, Scott, Responsible Responsive Design, A Book Apart, 2014. Responsive typography strategy. 

  7. Author’s headline typography. Display size (80px) with -0.03em letter-spacing and 1.05 line-height. Body text at default spacing with 1.7 line-height. 

  8. Author’s squint test results. xl (21px) and 2xl (25px) required weight differentiation (400 vs. 600) to pass visual distinction test. 

Related Posts

Color Science for Interface Designers: What I Learned Building a Zero-Color Site

I built a site with no colors — just white on absolute black with four opacity layers. Here's the color science that mad…

9 min read

Beauty and Brutalism: How I Designed blakecrosley.com at the Intersection

I built my site at the intersection of beauty and brutalism: structural honesty with precise typography on absolute blac…

7 min read

Design Systems for Startups: How I Built Mine Backwards

I built my design system backwards: tokens first, components never. A CLS bug taught me the cost of skipping tokens. I s…

8 min read