Technote

Performance optimization Advanced

Series Korean web typography Part 7 of 8

Metric overrides: stopping the jump when the font lands

Text jumps when a webfont lands not because it was late, but because the fallback had different widths and heights. Match the two and the swap leaves the layout untouched.

Attach a webfont with font-display: swap and the screen will change once. Usually it does not stop there: the whole layout moves — a heading folds from three lines to two, and everything beneath it is pulled upward.

Diagnosing this as “the font was slow” leads nowhere, because however fast the font arrives, the difference at the moment of the swap is unchanged. The cause is not speed. It is that the two typefaces have different metrics.

Different in what way

In two ways: glyph width and vertical metrics.

Different widths mean a different number of characters per line. If the fallback runs slightly wider, the same paragraph occupies one more line — and when the webfont lands and that line disappears, everything below rises.

Different vertical metrics (ascent, descent, line gap) mean the glyphs sit at a different height even at the same line-height. The line count can match and the text will still nudge up or down.

The same font-display: swap, with a very different outcome

Build a fallback family of your own

The trick is not to use the system font directly, but to wrap it in a new @font-face family whose metrics you override. CSS gives you four properties for this.

@font-face {
  font-family: 'Pretendard Fallback';   /* a name we invent */
  src: local('Malgun Gothic');
  size-adjust:        88.19%;   /* match width and apparent size */
  ascent-override:    95%;      /* height above the baseline */
  descent-override:   25%;      /* height below it */
  line-gap-override:  0%;
}

body {
  font-family: 'Pretendard Variable', 'Pretendard Fallback', sans-serif;
}

size-adjust does the heavy lifting. It scales the whole glyph set proportionally, so widths and apparent size are matched together. Matching widths means matching line breaks, and matching line counts means nothing below moves.

The other three align where the glyphs sit inside the line box. Every font carries its own ascent and descent values; normalising them means the baseline lands in the same place at a given line-height.

The numbers come from measurement

⚠ Do not copy the numbers above. Override values are specific to a pair of typefaces. Change the webfont and they change; and the fallback itself differs between operating systems.

Deriving them is not difficult. Render the same sentence in both faces, measure the widths, and use the ratio as your size-adjust. The canvas text-measurement API is enough.

const measure = (family) => {
  const c = document.createElement('canvas').getContext('2d');
  c.font = `100px ${family}`;
  return c.measureText('A sentence with Hangul and Latin ABC 123').width;
};

// the ratio that fits the fallback to the webfont
const adjust = measure('Pretendard Variable') / measure('Malgun Gothic');
console.log((adjust * 100).toFixed(2) + '%');

Use characters that actually appear in your body copy in the test string. Measuring Hangul alone can drift on real paragraphs that mix in Latin letters and numerals.

Residual error, and how to check

This technique does not reduce the error to zero. size-adjust scales everything by one ratio, so per-glyph width differences remain. In Korean paragraphs using word-break: keep-all, a word sitting right on the edge of a line can still tip the line count either way.

It is nonetheless a different order of problem from the unadjusted case. Verify with tools rather than eyes: record a page load in the browser’s performance panel and check whether layout-shift entries remain — and if they do, which element produced them.

Four steps — only step 2 is re-measured per pair of fonts

Layout shift and the wider performance metrics live in the Performance archive, and recording this kind of measurement as a before-and-after comparison is exactly what goes into the report in our optimization program.

Next part

With the letters arriving predictably, what is left is how to arrange them. The final part covers measure and vertical rhythm — the setting that gets long articles read to the end.

More on this topic

All technotes

Performance optimization Advanced

A front-end budget you can actually hold

Pages do not get heavy in one go. They get heavy through small, individually reasonable additions. A ceiling you actually check is what stops the accumulation.

Developers 8 min read

Performance optimization Advanced

A conversion audit: finding where people leave

Polishing a page nobody reaches is the most common waste. Walk the whole path end to end and the leak shows itself first.

Marketers 7 min read

Performance optimization Practical

The cost of pop-ups — search and conversion at once

An interstitial that covers the content on mobile is treated unfavourably in search, and the same interstitial costs conversions too. The levers are timing, trigger and dismissal.

Marketers 8 min read

₩270,000 · Join the program