To line up the numbers, we set the whole line in a monospace font. The line had Chinese in it.

The numbers lined up. The Chinese switched to a font we had never chosen.

Font fallback is silent

When the browser gets a character, it looks in the specified font first. If it isn’t there, it moves to the next font in the list. If none of them has it, it uses the system default.

Nothing in that process tells you. No console message, no error. The Chinese on that line just looks a little different from everywhere else.

In the design file that line usually holds only numbers, so it never shows up in review.

Two more traps

Putting a Chinese font after the monospace font doesn’t guarantee it gets used. The Chinese characters can drop all the way to the system default instead of stopping at the one you listed. For labels that contain Chinese, we now name the font outright rather than counting on the order of the font stack.

The other is free font services. Not every typeface has the Chinese version you want, and if you request it in the same call as the Latin version, the service hands you only the one it has and says nothing about what’s missing. The request succeeds with a 200, and half of what you asked for isn’t there.

What we do now

Wrap only the numbers that need fixed widths, not the whole line.

When verifying, we don’t ask the font API whether the font has loaded. Its “loaded” only means it tried, not that the screen is actually using it. We draw the text to a canvas and compare pixels. Two different fonts drawing the same character never produce the same pixels.