Skip to content
academia.sh

Lesson 12 / 22

Typographic Scale

Deriving size steps from a base and a ratio, how rounding distorts the neighboring-step ratio, computing the step budget, and placing interface levels onto scale steps.

Contents

The previous lesson tied the base size of body text to a typeface decision and computed that the same apparent size requires different nominal sizes across families. But the interface does not have a single size. The catalog interface carries at least five text levels: page title, record title, the borrow button’s text, author name, and metadata. What happens if these five numbers are each chosen individually?

What happens is this: the numbers are chosen independently, the ratios between them turn out random, and the 1.15 size-ratio threshold set in the Visual Hierarchy lesson is hit by chance in some pairs and missed in others. A scale is the structure that removes this chance: sizes are not chosen one by one, they are derived from a base and a ratio.

The Scale Is an Exponential Sequence

A typographic scale is a sequence of size steps that starts from a base size and is multiplied or divided by a fixed ratio. The size of step n is written as:

bn=Trnb_n = T \cdot r^{\,n}

Here TT is the base size, rr is the scale ratio, and nn is the step number. The base step is taken as zero; positive steps grow, negative steps shrink. The guarantee the scale gives is this: the ratio of any two neighboring steps is constant and equal to rr. Auditing the distinction comes down to looking at a single number.

This structure was introduced under the name modular scale in the Visual Presentation with CSS course; there, the problem was one of writing a declaration. Here, the problem is one of decision: which ratio, how many steps, and which level goes on which step.

Rounding Distorts the Fixed Ratio

The formula produces a continuous sequence; the screen, however, renders text more stably at integer pixel values. The difference looks negligible but directly distorts the neighboring-step ratio.

// scale.mjs — ratio-based typographic scale generation and rounding's effect on distinction

const BASE = 16;          // body text size (px)
const STEPS = [-2, -1, 0, 1, 2, 3, 4];
const RATIOS = [1.125, 1.200, 1.250, 1.333];
const THRESHOLD = 1.15;   // size-ratio threshold set in the Visual Hierarchy lesson

function scale(ratio) {
  return STEPS.map((n) => {
    const raw = BASE * Math.pow(ratio, n);
    return { n, raw, rounded: Math.round(raw) };
  });
}

for (const ratio of RATIOS) {
  const s = scale(ratio);
  console.log(`\n--- ratio ${ratio.toFixed(3)} ---`);
  console.log("step   raw (px)  rounded  neighbor ratio (raw)  neighbor ratio (rnd)  threshold");
  for (let i = 0; i < s.length; i++) {
    const a = s[i];
    if (i === 0) {
      console.log(
        `${String(a.n).padStart(4)} ${a.raw.toFixed(3).padStart(9)} ${String(a.rounded).padStart(8)}` +
          `${"-".padStart(23)}${"-".padStart(23)}${"-".padStart(11)}`
      );
      continue;
    }
    const previous = s[i - 1];
    const rawRatio = a.raw / previous.raw;
    const roundedRatio = a.rounded / previous.rounded;
    console.log(
      `${String(a.n).padStart(4)} ${a.raw.toFixed(3).padStart(9)} ${String(a.rounded).padStart(8)}` +
        `${rawRatio.toFixed(4).padStart(23)}${roundedRatio.toFixed(4).padStart(23)}` +
        `${(roundedRatio >= THRESHOLD ? "passed" : "FAILED").padStart(11)}`
    );
  }
}
--- ratio 1.125 ---
step   raw (px)  rounded  neighbor ratio (raw)  neighbor ratio (rnd)  threshold
  -2    12.642       13                      -                      -          -
  -1    14.222       14                 1.1250                 1.0769     FAILED
   0    16.000       16                 1.1250                 1.1429     FAILED
   1    18.000       18                 1.1250                 1.1250     FAILED
   2    20.250       20                 1.1250                 1.1111     FAILED
   3    22.781       23                 1.1250                 1.1500     passed
   4    25.629       26                 1.1250                 1.1304     FAILED

--- ratio 1.200 ---
step   raw (px)  rounded  neighbor ratio (raw)  neighbor ratio (rnd)  threshold
  -2    11.111       11                      -                      -          -
  -1    13.333       13                 1.2000                 1.1818     passed
   0    16.000       16                 1.2000                 1.2308     passed
   1    19.200       19                 1.2000                 1.1875     passed
   2    23.040       23                 1.2000                 1.2105     passed
   3    27.648       28                 1.2000                 1.2174     passed
   4    33.178       33                 1.2000                 1.1786     passed

--- ratio 1.250 ---
step   raw (px)  rounded  neighbor ratio (raw)  neighbor ratio (rnd)  threshold
  -2    10.240       10                      -                      -          -
  -1    12.800       13                 1.2500                 1.3000     passed
   0    16.000       16                 1.2500                 1.2308     passed
   1    20.000       20                 1.2500                 1.2500     passed
   2    25.000       25                 1.2500                 1.2500     passed
   3    31.250       31                 1.2500                 1.2400     passed
   4    39.063       39                 1.2500                 1.2581     passed

--- ratio 1.333 ---
step   raw (px)  rounded  neighbor ratio (raw)  neighbor ratio (rnd)  threshold
  -2     9.005        9                      -                      -          -
  -1    12.003       12                 1.3330                 1.3333     passed
   0    16.000       16                 1.3330                 1.3333     passed
   1    21.328       21                 1.3330                 1.3125     passed
   2    28.430       28                 1.3330                 1.3333     passed
   3    37.897       38                 1.3330                 1.3571     passed
   4    50.517       51                 1.3330                 1.3421     passed

The first scale fails. Choosing a ratio of 1.125 means choosing a distinction below the threshold (1.15); rounding neither fixes this nor makes it worse, it only makes it irregular. The realized ratios oscillate between 1.0769 and 1.1500: one step pair grows by 7.7 percent, another by 15 percent — exactly double. The scale’s one guarantee — that the neighboring ratio stays constant — disappears along with the rounding.

The growth of the oscillation at small sizes is not a coincidence. The rounding error is at most half a pixel; this error’s effect on the ratio is inversely proportional to size. Half a pixel at 13 pixels is a 3.8 percent deviation; at 39 pixels it is a 1.3 percent deviation. The scale’s low end is three times as fragile as its high end.

In the other three scales, every rounded ratio clears the threshold. As the ratio grows, the oscillation’s effect shrinks proportionally: in the 1.333-ratio scale, the realized ratios fall between 1.3125 and 1.3571, meaning the widest ratio is 1.034 times the narrowest.

The rule that follows can be written this way: the scale ratio is chosen distinctly larger than the distinction threshold. A ratio equal or close to the threshold falls below it in some step pairs, depending on which direction the rounding happens to work.

The Step Budget

Growing the ratio has a cost. The size range the interface can use is bounded: readability sets the low end, the space it takes up on screen sets the high end. As the ratio grows, fewer steps fit into this range.

// steps.mjs — the scale's step budget and placing levels onto steps

const BASE = 16;
const SMALLEST = 12;   // smallest allowed size for non-body text
const LARGEST = 40;    // largest heading size the catalog interface needs

console.log("ratio   step count (12-40 px range)  first step  last step");
for (const ratio of [1.125, 1.2, 1.25, 1.333, 1.5]) {
  const lowStep = Math.ceil(Math.log(SMALLEST / BASE) / Math.log(ratio));
  const highStep = Math.floor(Math.log(LARGEST / BASE) / Math.log(ratio));
  const count = highStep - lowStep + 1;
  const first = Math.round(BASE * Math.pow(ratio, lowStep));
  const last = Math.round(BASE * Math.pow(ratio, highStep));
  console.log(
    `${ratio.toFixed(3)} ${String(count).padStart(28)} ${String(first).padStart(12)} ${String(last).padStart(11)}`
  );
}

// The catalog interface's levels, placed onto the steps of a 1.25-ratio scale.
const RATIO = 1.25;
const size = (n) => Math.round(BASE * Math.pow(RATIO, n));

const levels = [
  { name: "page title",   step: 3, weight: 700 },
  { name: "record title", step: 1, weight: 600 },
  { name: "button text",  step: 0, weight: 600 },
  { name: "author",       step: 0, weight: 400 },
  { name: "metadata",     step: -1, weight: 400 },
];

const THRESHOLD = { sizeRatio: 1.15, weightDiff: 200 };

console.log("\nlevel           step  size(px)  weight");
for (const l of levels) {
  console.log(
    `${l.name.padEnd(15)} ${String(l.step).padStart(4)} ${String(size(l.step)).padStart(9)} ${String(l.weight).padStart(7)}`
  );
}

console.log("\nneighboring level pair           size ratio  weight diff  passing channel");
for (let i = 0; i < levels.length - 1; i++) {
  const upper = levels[i];
  const lower = levels[i + 1];
  const sizeRatio = size(upper.step) / size(lower.step);
  const weightDiff = upper.weight - lower.weight;
  const passing = [];
  if (sizeRatio >= THRESHOLD.sizeRatio) passing.push("size");
  if (weightDiff >= THRESHOLD.weightDiff) passing.push("weight");
  const label = `${upper.name} > ${lower.name}`;
  console.log(
    `${label.padEnd(32)} ${sizeRatio.toFixed(3).padStart(10)} ${String(weightDiff).padStart(13)}  ${passing.length ? passing.join("+") : "WEAK"}`
  );
}
ratio   step count (12-40 px range)  first step  last step
1.125                           10           13          36
1.200                            7           13          40
1.250                            6           13          39
1.333                            5           12          38
1.500                            3           16          36

level           step  size(px)  weight
page title         3        31     700
record title       1        20     600
button text        0        16     600
author             0        16     400
metadata          -1        13     400

neighboring level pair           size ratio  weight diff  passing channel
page title > record title             1.550           100  size
record title > button text            1.250             0  size
button text > author                  1.000           200  weight
author > metadata                     1.231             0  size

The first table shows the real trade-off in choosing a scale ratio. The same 12–40 pixel range fits ten steps at a ratio of 1.125, three steps at 1.5. The previous computation showed that a 1.125 ratio cannot clear the threshold; this table shows that a 1.5 ratio leaves room for only three levels. The catalog interface needs five levels, so a 1.5 ratio is eliminated outright. The remaining candidates are 1.2, 1.25, and 1.333; all clear the threshold and all fit five levels.

The decision was made in favor of a 1.25 ratio. The rationale is the slack in the second table: six steps leave a one-step margin for five levels. A scale that is completely full means that adding a level later requires recomputing the whole scale.

Not Every Level Needs a New Step

Two points stand out in the third table’s level placement.

First, button text and author name sit at the same step: both step zero, 16 pixels. The size ratio is 1.000; the size channel produces no distinction. The distinction is built in weight, and the 200-unit difference clears the threshold. The two-channel rule from the Visual Hierarchy lesson is met here by a third channel: button text sits on a filled surface, author name on a plain background. Surface is a channel that does not appear in this table but is genuinely at work, and it is the subject of the Color System lesson.

Second, the comparison in the fourth row is not actually a hierarchical pair. Button text and author name do not compete in the same visual area; one is in the action zone, the other inside the record row. The neighbor audit treats the levels as a sorted list, but hierarchy is meaningful only among elements seen at the same time. Because the table produced no warning here, this distinction caused no problem, but whether a row marked WEAK is a real problem is always checked with this same question.

The last row closes out a finding from the first lesson. There, the distinction between author and metadata stood only in the contrast channel and was counted as one-legged. The scale, by lowering metadata to 13 pixels instead of 14, raised the size ratio to 1.231; the distinction now stands in both size and contrast. The step decision solved, through the scale’s own structure, a problem that choosing sizes one by one could not.

The Scale’s Written Form

If the scale remains a computation, it gets redone and drifts at every use. Its written form is the conversion of steps into named values:

:root {
  --size--1: 13px;
  --size-0: 16px;
  --size-1: 20px;
  --size-2: 25px;
  --size-3: 31px;
}

Names carrying the step number are more durable than names carrying meaning like “heading” or “small.” Meaning-bearing names start lying when the interface changes: a value named “heading” one day gets used somewhere that is not a heading. A step number, by contrast, only states its position in the scale, and that position does not change.

This list has no intermediate value, and it should not. When the feeling arises that a level needs 18 pixels, the answer is not to add a new variable but to decide which step the level belongs to. Every number that steps outside the scale cancels the scale’s guarantee at that point.

Summary

  • A typographic scale derives sizes exponentially from a base and a ratio; the guarantee it provides is that the neighboring-step ratio stays constant.
  • Rounding to integer pixels breaks this constancy; the deviation’s effect on the ratio is larger at small sizes, so the scale’s low end is its most fragile point.
  • The scale ratio is chosen not equal to the distinction threshold but distinctly larger than it; a ratio close to the threshold drops below it in some step pairs through rounding.
  • As the ratio grows, fewer steps fit into a given size range; choosing a ratio is a trade-off between distinguishing power and step budget.
  • Not every level needs a new step; two levels at the same step can be separated in the weight or surface channel.
  • The scale is written as named step values; adding an intermediate value cancels the scale’s guarantee at that point.

Next Step

The scale said how large the text would be, not how wide. When the summary paragraph in a record detail spreads across the full column, lines grow long, and the eye starts missing its target as it returns from the end of one line to the start of the next. The next lesson computes line length in characters, ties the measure to column width, and shows why leading has to be adjusted together with line length.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close