# Fewer Sizes, More Contrast

**SHOULD** · **ID:** `content-impeccable-type-scale-contrast` · **Category:** content
**Source:** [impeccable](https://impeccable.style/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/content-impeccable-type-scale-contrast

> SHOULD: Generate every type step from one ratio of at least 1.25 (major third), 1.333, or 1.5 rather than adding near-identical sizes — a page with 3 or more distinct sizes whose largest-to-smallest ratio is under 2.0 has no hierarchy left to squint at.

Generate every step from one ratio of at least 1.25 instead of adding near-identical sizes

The named failure is "too many font sizes that are too close together (14px, 15px, 16px, 18px...)": each new size was added to solve a local problem and none of them are far enough apart to signal rank, so the page reads as one grey slab. impeccable's detector flags a page with 3 or more distinct sizes whose largest-to-smallest ratio is under 2.0. Pick a single ratio (1.25 major third, 1.333 perfect fourth, or 1.5), generate five steps from it, and the hierarchy survives a squint test.

## Bad — do not do this

`content-impeccable-type-scale-contrast-bad`

```tsx
const STEPS = [
  { px: 20, weight: 600, text: 'Deployment overview' },
  { px: 18, weight: 600, text: 'Production build' },
  { px: 16, weight: 400, text: 'The last build finished 4 minutes ago.' },
  { px: 15, weight: 400, text: 'Triggered by a push to main.' },
  { px: 14, weight: 400, text: 'Region iad1 · 1.2s' },
];

const sizes = STEPS.map((s) => s.px);
const ratio = Math.max(...sizes) / Math.min(...sizes);

export function ImpeccableTypeScaleContrastBad() {
  return (
    <div className="space-y-3">
      <div className="space-y-2 rounded-lg border border-border bg-card p-4">
        {STEPS.map((step) => (
          <p
            key={step.px}
            className="text-foreground"
            style={{ fontSize: `${step.px}px`, fontWeight: step.weight, lineHeight: 1.4 }}
          >
            {step.text}
          </p>
        ))}
      </div>

      <div className="flex flex-wrap items-center gap-2 text-xs">
        <span className="rounded border border-border bg-muted px-2 py-1 font-mono text-error">
          {sizes.length} sizes · {sizes.join(' / ')}px
        </span>
        <span className="rounded border border-border bg-muted px-2 py-1 font-mono text-error">
          largest ÷ smallest = {ratio.toFixed(1)}:1
        </span>
      </div>

      <p className="text-xs text-error">
        Five sizes, but every step is only a pixel or two apart, so the whole block reads as one
        undifferentiated grey slab — squint at it and the heading disappears into the metadata. The
        detector flags 3 or more distinct sizes whose largest-to-smallest ratio is under 2.0: that
        is flat hierarchy. More sizes did not buy more structure; they only bought more decisions.
      </p>
    </div>
  );
}
```

## Good — do this

`content-impeccable-type-scale-contrast-good`

```tsx
// A 1.333 (perfect fourth) scale from a 16px base: 12 / 16 / 21 / 28 / 37
const STEPS = [
  { px: 37, weight: 600, text: 'Deployment overview' },
  { px: 21, weight: 600, text: 'Production build' },
  { px: 16, weight: 400, text: 'The last build finished 4 minutes ago.' },
  { px: 16, weight: 400, text: 'Triggered by a push to main.' },
  { px: 12, weight: 400, text: 'Region iad1 · 1.2s' },
];

const sizes = [...new Set(STEPS.map((s) => s.px))];
const ratio = Math.max(...sizes) / Math.min(...sizes);

export function ImpeccableTypeScaleContrastGood() {
  return (
    <div className="space-y-3">
      <div className="space-y-2 rounded-lg border border-border bg-card p-4">
        {STEPS.map((step, i) => (
          <p
            key={i}
            className={step.px === 12 ? 'text-muted-foreground' : 'text-foreground'}
            style={{ fontSize: `${step.px}px`, fontWeight: step.weight, lineHeight: 1.4 }}
          >
            {step.text}
          </p>
        ))}
      </div>

      <div className="flex flex-wrap items-center gap-2 text-xs">
        <span className="rounded border border-border bg-muted px-2 py-1 font-mono text-success">
          {sizes.length} sizes · 12 / 16 / 21 / 28 / 37px (ratio 1.333)
        </span>
        <span className="rounded border border-border bg-muted px-2 py-1 font-mono text-success">
          largest ÷ smallest = {ratio.toFixed(1)}:1
        </span>
      </div>

      <p className="text-xs text-success">
        One ratio (1.333, a perfect fourth) generates every step, and the two body lines share a
        single size instead of inventing a new one. Squint: the heading, the section, the body, and
        the metadata separate instantly. Pick one ratio — 1.25 (major third), 1.333, or 1.5 — and
        five steps will cover nearly any interface.
      </p>
    </div>
  );
}
```

## References

- [impeccable](https://impeccable.style/)
- [Practical Typography: Type composition](https://practicaltypography.com/type-composition.html)
- [MDN: font-size](https://developer.mozilla.org/en-US/docs/Web/CSS/font-size)
