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

Our pages render identically at 1280px and at 4K, and our prose runs 78 characters to the line

Every typography guide gives you the same number. Bringhurst says 66 characters a line is ideal for single-column text. The looser version of the advice is 45 to 75. CSS has had a unit for this since forever, ch, and the

Every typography guide gives you the same number. Bringhurst says 66 characters a line is ideal for single-column text. The looser version of the advice is 45 to 75. CSS has had a unit for this since forever, ch, and the advice usually arrives as max-width: 65ch.

What almost nobody does is measure what their site actually renders. I had never measured mine, so I did it across all 76 public pages of Nakodo, at four viewport widths, two different ways.

The second part of that sentence turned out to be pointless, and that is the first finding.

The site stops responding at 768 pixels

I ran the sweep at 1280, 1920, 2560 and 3840 pixels wide. Here is the result in full:

Width Paragraphs Median measure p90 Longest
1280 1,755 78ch 82ch 136ch
1920 1,755 78ch 82ch 136ch
2560 1,755 78ch 82ch 136ch
3840 1,755 78ch 82ch 136ch

Not similar. Identical. All 76 pages have the same paragraph line counts at 3840 as at 1280, and every paragraph box is the same number of pixels wide.

That is because the widest element inside main is 768 pixels on 68 of the 76 pages, 1024 on six of them and 1152 on one. The only thing that grows past that is a full-bleed panel on the home page, which stretches the whole width because it is a background.

So at 4K, the readable part of a content page is a 768 pixel ribbon down the middle of a 3840 pixel screen. One fifth of the display. Everything above 1280 is wallpaper.

I am not going to pretend that is a bug. A guide is a column of prose, and prose does not want to be 3840 pixels wide. But it was worth knowing that the site has no design above lg, that nothing was decided for those widths, and that the measurement is therefore a single number rather than a curve.

Two ways to measure a line

The empirical way is to count rendered lines. A Range over a paragraph's contents returns one client rect per line box, so the distinct rect tops give you the real line count after the browser has done its wrapping:

const range = document.createRange();
range.selectNodeContents(p);
const tops = new Set([...range.getClientRects()]
  .filter((r) => r.height > 4 && r.width > 2)
  .map((r) => Math.round(r.top)));
const charsPerLine = text.length / tops.size;

That gives the median 77 characters a line across the site. It has a known bias: the last line of a paragraph is usually short, so the average is lower than the typographic measure. A two-line paragraph whose second line holds three words drags the number down a long way.

The typographic way is to measure the box in characters, which is what ch is for. There is no getComputedStyle property for it, so you ask the browser by making an element one ch wide inside the paragraph you are measuring, so it inherits the right font, and reading its rect back:

const probe = document.createElement("span");
probe.style.cssText = "position:absolute;visibility:hidden;width:1ch";
p.appendChild(probe);
const ch = probe.getBoundingClientRect().width;
probe.remove();
const measure = p.getBoundingClientRect().width / ch;

That gives 78. The two methods landing one character apart was more reassuring than either number on its own.

A caveat on ch: it is the advance width of the digit zero, which in most proportional fonts is wider than the average lowercase letter. So a box of 78ch typically fits rather more than 78 characters of real English. Both of my numbers are estimates of the same thing from opposite directions, and the honest conclusion is "somewhere around 78", not "78.0".

The distribution, which is where the problem is

1,755 paragraphs of at least 40 characters inside main. Grouped by measure:

Measure Paragraphs
20 to 29ch 7
30 to 39ch 334
40 to 49ch 74
50 to 59ch 20
60 to 69ch 161
70 to 79ch 528
80 to 89ch 625
130ch and over 3

11 per cent of the paragraphs on this site sit in the 45 to 75 range. 628 of them are over 80.

The shape is two humps, and each hump is a component rather than a decision about reading.

The big hump at 70 to 89 is the prose column. 626 paragraphs are in a box exactly 704 pixels wide and 351 are in one 672 pixels wide, which is max-w-3xl and max-w-2xl with padding taken off. At the body size of 15 pixels, 704 pixels is 78ch.

The hump at 30 to 39 is card blurbs: 267 paragraphs in a 302 pixel box, which are the two-line summaries in the grids on the hub pages like /guides and /youtubers. The narrowest-measure pages on the site are those hubs, at a median of 33ch, because they are not pages of prose at all.

The three paragraphs over 130ch are a measurement artefact worth describing, because it is the kind of thing that makes a sweep lie. They are single-line paragraphs of 46 to 48 characters sitting in a 1,088 pixel box. The box is wide, the text is short, and no line ever gets near the width, so the measure is a fact about the container and not about anything anybody reads. Measure is only meaningful for text that wraps.

Three more paragraphs came back with a box width of one pixel, which turned out to be sr-only text: the 1px clipped box is the mechanism, so those are correctly excluded rather than a bug.

15 pixels is the actual cause

The font sizes in that paragraph set are 15px for 1,245 of them, 14px for 351, 17px for 77 and 26px for 72.

That is the lever. A measure is a ratio of box width to character width, so there are two ways to pull 78ch down into the range, and only one of them is any good.

Narrowing the column from 704 to 640 pixels gets you to about 71ch and makes the page feel thinner without making anything easier to read.

Raising the body text from 15px to 16px gets you to about 73ch, and the text is also bigger. The counterintuitive version of the typography advice is that when your measure is too long, the first thing to try is larger text rather than a narrower column, because the reader gets both improvements from one change.

I am going to do the second one. 15px was a choice made for density on the app side of the product that leaked into the marketing pages, where there is nothing to be dense about.

Check it yourself

On any page of nakodo.app, this prints the measure of every wrapping paragraph:

const range = document.createRange();
console.table([...document.querySelectorAll("main p")]
  .filter((p) => p.textContent.trim().length > 40 && p.getBoundingClientRect().width > 5)
  .map((p) => {
    const probe = document.createElement("span");
    probe.style.cssText = "position:absolute;visibility:hidden;width:1ch";
    p.appendChild(probe);
    const ch = probe.getBoundingClientRect().width;
    probe.remove();
    range.selectNodeContents(p);
    const lines = new Set([...range.getClientRects()].filter((r) => r.height > 4).map((r) => Math.round(r.top))).size;
    return { measure: Math.round(p.getBoundingClientRect().width / ch), lines,
             perLine: Math.round(p.textContent.trim().length / lines) };
  }));

Then make the window 3840 pixels wide, or set that width in the device toolbar, and run it again. Nothing in the output moves, which is the whole of the first half of this post.

A guide page is the clearest place to see the long measure, the guides hub the clearest place to see the short one, and both of them will still say 78 and 33 until I ship the font size change.

What I took from it

  1. Measure, do not assume. I would have guessed this site was at 65 to 70 characters, because the column felt right. It is at 78, and 89 per cent of its paragraphs are outside the range every typography book recommends.
  2. Measure in two units. Characters per rendered line and box width in ch have opposite biases. They agreed here, and if they had not, that disagreement would have been the finding.
  3. A sweep needs an exclusion rule before it needs a chart. Six of my 1,755 paragraphs were single lines in wide boxes or 1px screen-reader text, and all six sat at the extremes of the distribution.
  4. Having no design above 1280 is a decision, so decide it. Right now the answer to "what does this site look like on a 4K monitor" is "exactly like a 1280 monitor with more wallpaper", which is defensible for prose and a waste for the home page.
📰 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.