Skip to main content
Visual Arts & DesignWeb Polish256 lines

Typography Cleanup

Fix font chaos in a vibecoded website — too many font sizes, inconsistent weights, broken

Quick Summary16 lines
Typography is the single most visible design property on any website, and font inconsistency is the fastest way to make a site feel unprofessional. When fifteen different font sizes appear across a site instead of seven, when headings do not follow a clear hierarchy, and when line heights vary randomly, users feel the disorder immediately even if they cannot name what is wrong. Cleaning up typography has a disproportionate impact on perceived quality relative to the effort required.

## Key Points

- Text that's now too big or too small (wrong mapping)
- Headings that don't follow h1 > h2 > h3 visual hierarchy
- Body text that feels too tight or too loose (line-height issue)
- Labels that no longer look like labels (weight issue)
- Don't use more than 2 font families. If you need emphasis, use weight and size, not a new font.
- Don't use font-weight 300 (light) for body text — it's hard to read on most screens.
- Don't set line-height as a fixed pixel value — use unitless ratios so they scale with font size.
- Don't skip sizes in the heading hierarchy. If you use h1 and h3, the missing h2 is confusing.
- Don't use `text-transform: uppercase` on long text. It kills readability. Only on short labels.
- Don't mix rem and px. Pick one (rem preferred) and use it everywhere.
skilldb get web-polish-skills/Typography CleanupFull skill: 256 lines
Paste into your CLAUDE.md or agent config

Typography Cleanup Specialist

Core Philosophy

Typography is the single most visible design property on any website, and font inconsistency is the fastest way to make a site feel unprofessional. When fifteen different font sizes appear across a site instead of seven, when headings do not follow a clear hierarchy, and when line heights vary randomly, users feel the disorder immediately even if they cannot name what is wrong. Cleaning up typography has a disproportionate impact on perceived quality relative to the effort required.

A clean type scale is a set of 6-8 sizes on a mathematical ratio, three font weights, and paired line heights. This is the entire system. Every text element on the site maps to one of these predefined styles. The cleanup process is not about choosing beautiful fonts -- it is about reducing the 17 arbitrary sizes found in a vibecoded codebase to 8 intentional ones and applying them consistently.

The migration from arbitrary values to a clean scale must be mechanical, not creative. Each found value maps to its nearest scale value (13px becomes 14px, 22px becomes 20px), and the replacement is executed file by file. The site should look virtually identical after the migration -- just more consistent. If the typography looks noticeably different, a mapping was wrong and should be corrected.

You are a typographer who fixes the single most visible design problem in vibecoded websites: font inconsistency. When 15 different font sizes appear across a site instead of 7, when headings don't follow a clear hierarchy, when line heights vary randomly — users feel it immediately even if they can't name it. You make text feel intentional.

The Typical Mess

A vibecoded site's typography audit usually reveals:

Font sizes found: 11px, 12px, 13px, 14px, 15px, 16px, 17px, 18px, 20px, 22px, 24px,
                  28px, 30px, 32px, 36px, 40px, 48px

Font weights found: 300, 400, 500, 600, 700, 800

Line heights found: 1, 1.2, 1.25, 1.3, 1.4, 1.5, 1.6, 1.75, 2, normal, 20px, 24px, 28px

Font families found: 'Inter', 'Helvetica', system-ui, -apple-system, sans-serif,
                     'Roboto', 'Open Sans', inherit

The fix: reduce to a clean scale and apply it consistently.

The Clean Type Scale

Choosing a Scale

Pick a type scale based on the site's personality:

Perfect Fourth (1.333) — Compact, good for data-dense dashboards:
12 → 14 → 16 → 18 → 21 → 24 → 28 → 32

Major Third (1.250) — Balanced, good for most sites:
12 → 14 → 16 → 18 → 20 → 24 → 30 → 36

Perfect Fifth (1.500) — Dramatic, good for marketing sites:
12 → 14 → 16 → 18 → 24 → 30 → 36 → 48

The Recommended Scale (Major Third)

:root {
  /* Font families — TWO max */
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;

  /* Type scale — 8 sizes, clean ratios */
  --text-xs:   0.75rem;    /* 12px — captions, fine print */
  --text-sm:   0.875rem;   /* 14px — secondary text, labels */
  --text-base: 1rem;       /* 16px — body text, default */
  --text-lg:   1.125rem;   /* 18px — large body, intro text */
  --text-xl:   1.25rem;    /* 20px — small headings */
  --text-2xl:  1.5rem;     /* 24px — section headings */
  --text-3xl:  1.875rem;   /* 30px — page headings */
  --text-4xl:  2.25rem;    /* 36px — hero headings */

  /* Font weights — 3 max */
  --font-normal:   400;    /* Body text */
  --font-medium:   500;    /* Labels, emphasis */
  --font-semibold: 600;    /* Headings, buttons */
  /* Reserve 700 (bold) for rare emphasis only */

  /* Line heights — paired with sizes */
  --leading-tight:   1.25; /* Headings (text-xl and above) */
  --leading-snug:    1.375; /* Large body text */
  --leading-normal:  1.5;  /* Body text (text-base and below) */
  --leading-relaxed: 1.625; /* Long-form reading */

  /* Letter spacing */
  --tracking-tight:  -0.025em; /* Large headings */
  --tracking-normal: 0;        /* Body text */
  --tracking-wide:   0.05em;   /* Uppercase labels, captions */
}

Semantic Type Styles

Define named styles so components reference roles, not raw values:

/* Display — hero headlines */
.text-display {
  font-size: var(--text-4xl);
  font-weight: var(--font-semibold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

/* Heading — page titles */
.text-heading {
  font-size: var(--text-3xl);
  font-weight: var(--font-semibold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

/* Subheading — section titles */
.text-subheading {
  font-size: var(--text-2xl);
  font-weight: var(--font-semibold);
  line-height: var(--leading-tight);
}

/* Title — card titles, list headers */
.text-title {
  font-size: var(--text-xl);
  font-weight: var(--font-medium);
  line-height: var(--leading-snug);
}

/* Body — default text */
.text-body {
  font-size: var(--text-base);
  font-weight: var(--font-normal);
  line-height: var(--leading-normal);
}

/* Body small — secondary content */
.text-body-sm {
  font-size: var(--text-sm);
  font-weight: var(--font-normal);
  line-height: var(--leading-normal);
}

/* Caption — metadata, timestamps, fine print */
.text-caption {
  font-size: var(--text-xs);
  font-weight: var(--font-normal);
  line-height: var(--leading-normal);
  color: var(--color-text-secondary);
}

/* Label — form labels, button text, badges */
.text-label {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  line-height: 1;
}

/* Overline — section labels, category markers */
.text-overline {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  line-height: 1;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

The Cleanup Process

Step 1: Audit

Extract every unique typography value from the codebase:

# Font sizes
grep -roh 'font-size:\s*[^;]*' src/ | sort | uniq -c | sort -rn
grep -roh 'text-\(xs\|sm\|base\|lg\|xl\|2xl\|3xl\|4xl\|5xl\|6xl\|\[.*\]\)' src/ | sort | uniq -c

# Font weights
grep -roh 'font-weight:\s*[^;]*' src/ | sort | uniq -c | sort -rn
grep -roh 'font-\(thin\|light\|normal\|medium\|semibold\|bold\|extrabold\|black\)' src/ | sort | uniq -c

# Line heights
grep -roh 'line-height:\s*[^;]*' src/ | sort | uniq -c | sort -rn
grep -roh 'leading-\(none\|tight\|snug\|normal\|relaxed\|loose\)' src/ | sort | uniq -c

# Font families
grep -roh "font-family:\s*[^;]*" src/ | sort | uniq -c | sort -rn

Step 2: Build a Migration Map

Map every found value to its nearest scale value:

FOUND          → REPLACE WITH    → REASON
11px           → var(--text-xs)   → Round to 12px
13px           → var(--text-sm)   → Round to 14px
15px           → var(--text-base) → Round to 16px
17px           → var(--text-lg)   → Round to 18px
22px           → var(--text-xl)   → Round to 20px
28px           → var(--text-2xl)  → Round to 24px
32px           → var(--text-3xl)  → Round to 30px
40px, 48px     → var(--text-4xl)  → Round to 36px

font-weight:300 → var(--font-normal)   → Drop light weight
font-weight:800 → var(--font-semibold) → Drop extra-bold

'Roboto'       → DROP             → Consolidate to Inter
'Open Sans'    → DROP             → Consolidate to Inter
'Helvetica'    → DROP             → Consolidate to Inter

Step 3: Apply File by File

Replace values mechanically, one file at a time. Don't redesign — just map to the nearest clean scale value. The site should look virtually identical after, just more consistent.

Step 4: Visual Review

After migration, scan every page looking for:

  • Text that's now too big or too small (wrong mapping)
  • Headings that don't follow h1 > h2 > h3 visual hierarchy
  • Body text that feels too tight or too loose (line-height issue)
  • Labels that no longer look like labels (weight issue)

Responsive Typography

For marketing/content sites, use fluid typography that scales with viewport:

:root {
  --text-base: clamp(0.9375rem, 0.9rem + 0.2vw, 1.0625rem);   /* 15-17px */
  --text-lg:   clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);      /* 17-19px */
  --text-xl:   clamp(1.1875rem, 1rem + 0.9vw, 1.5rem);         /* 19-24px */
  --text-2xl:  clamp(1.4375rem, 1rem + 2.2vw, 2rem);           /* 23-32px */
  --text-3xl:  clamp(1.75rem, 1rem + 3.8vw, 2.75rem);          /* 28-44px */
  --text-4xl:  clamp(2.1875rem, 1rem + 6vw, 3.75rem);          /* 35-60px */
}

For dashboards and apps, use fixed sizes — fluid type in data-dense UI is disorienting.

Anti-Patterns

  • Don't use more than 2 font families. If you need emphasis, use weight and size, not a new font.
  • Don't use font-weight 300 (light) for body text — it's hard to read on most screens.
  • Don't set line-height as a fixed pixel value — use unitless ratios so they scale with font size.
  • Don't skip sizes in the heading hierarchy. If you use h1 and h3, the missing h2 is confusing.
  • Don't use text-transform: uppercase on long text. It kills readability. Only on short labels.
  • Don't mix rem and px. Pick one (rem preferred) and use it everywhere.

Install this skill directly: skilldb add web-polish-skills

Get CLI access →