Dev.to WebDev 🛠 Dev 👁 0 📖 4 min read

What type scale is a site really using? Measuring it from computed font sizes

"Modular scale, ratio 1.25" is a nice thing to put in a design doc. When you inherit a site, or want to match one, you rarely get that doc. You get a page and DevTools. Here is how I measure the scale a page actually us

"Modular scale, ratio 1.25" is a nice thing to put in a design doc. When you inherit a site, or want to match one, you rarely get that doc. You get a page and DevTools.

Here is how I measure the scale a page actually uses, what it looked like on three demo sites I built, and where the single "ratio" number stops being useful.

Step 1: list the sizes, weighted by text

Clicking headings one by one in DevTools misses sizes and tells you nothing about which size carries the body text. Instead, walk every visible text node and add up characters per computed font size. Paste this in the console:

(() => {
  const sizes = new Map();
  const walk = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
  while (walk.nextNode()) {
    const text = walk.currentNode.textContent.trim();
    const el = walk.currentNode.parentElement;
    if (!text || !el.checkVisibility()) continue;
    const px = Math.round(parseFloat(getComputedStyle(el).fontSize));
    sizes.set(px, (sizes.get(px) || 0) + text.length);
  }
  return [...sizes].sort((a, b) => b[0] - a[0]);
})()

On Northwind Roasters, a fictional coffee shop I use for demos, at 1280px wide it returns [size in px, characters] pairs:

[[64, 44], [40, 30], [22, 50], [17, 486], [15, 85], [14, 145]]

Run it at the viewport you care about. If the headings use clamp() or media queries, a phone width gives different numbers.

Step 2: the base is the size with the most text

486 characters at 17px, far more than anything else, so the body size is 17px, not the 16px you might assume. That matters: if you rebuild this site with Tailwind's default text-base (16px), every paragraph comes out a pixel smaller and the line lengths change.

Step 3: a ratio from the steps above the base

Sizes above the base: 22, 40, 64. If the scale were geometric, each step would multiply by the same ratio r, so 17 × r³ = 64:

const ratio = (base, above) => (Math.max(...above) / base) ** (1 / above.length);
ratio(17, [22, 40, 64]); // 1.556

A second demo site, Ledgerline (a fictional accounting app), has a 16px base and 18, 20, 28 and 60 above it:

ratio(16, [18, 20, 28, 60]); // 1.392

That is close to the augmented fourth (1.414) from the classic named ratios. Close is all it is.

Why the ratio is only a summary

Go back to Northwind and look at the actual steps:

  • 22 / 17 = 1.29
  • 40 / 22 = 1.82
  • 64 / 40 = 1.60

No single ratio there. If you regenerate the scale from base 17 and ratio 1.556, you get 26.4, 41.1 and 64. The h1 matches, the h2 is close, and the h3 is 4.4px too big. That is a visibly different card title.

The third site shows how fragile the number is. Afterhours (a fictional dev tool) gives sizes above its 16px base of 19, 20 and 66:

ratio(16, [19, 20, 66]); // 1.604
ratio(16, [19, 66]);     // 2.031

The 20px size covers 10 characters on the whole page, probably one stray label. Drop it and the "ratio" jumps from 1.60 to 2.03. In practice this site has a huge display heading and then body-ish sizes, and no ratio describes that well.

So I use the ratio as a one-line description ("base 17, grows about 1.56 per step") and keep the measured sizes as the actual tokens:

:root {
  --text-sm: 0.875rem;    /* 14px */
  --text-base: 1.0625rem; /* 17px */
  --text-xl: 1.375rem;    /* 22px, h3 */
  --text-4xl: 2.5rem;     /* 40px, h2 */
  --text-6xl: 4rem;       /* 64px, h1 */
}

Measure line height and tracking too

Size alone does not make a heading look right. Click one heading per step in DevTools and read line-height and letter-spacing from Computed. On Northwind:

Step Size Line height Letter spacing
h1 64px 1.04 -1.28px (-0.02em)
h2 40px 1.1 -0.4px (-0.01em)
h3 22px 1.25 0
body 17px 1.6 0

The pattern is the usual one: the bigger the text, the tighter the leading and tracking. The other two sites tighten their h1 harder: Afterhours at 66px uses -2.64px (-0.04em), Ledgerline at 60px uses -2.7px (-0.045em). Convert tracking to em when you copy it, so it still fits if you change the size.

The short version

  1. List sizes weighted by characters, at the viewport you care about.
  2. The size with the most text is the base.
  3. Compute a ratio if you want a description, but copy the real sizes.
  4. Take line height and letter spacing with each step.

If you'd rather not do this by hand, I made a Chrome extension, Stylasso, that reads the type scale along with the fonts and colors and gives base, ratio and each step's line height and tracking. The numbers above match its output for these demo sites, except that it drops the stray 20px size on Afterhours (that's where its 2.031 comes from). There's a short guide here: find out what font a website is using, with its type scale. The snippet works fine without it.

Written with help from an AI assistant. The sizes come from running the snippet above on the three demo pages, and the ratios from the code in this post.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.