Frontend5 min read
The icon font, taken apart
A legacy icon font, read with opentype.js and turned into 18 components that take currentColor. The font file left the bundle, and the icons stopped being characters.
What an icon font costs you
An icon font is a clever answer to a 2013 question. The icons are text, so they inherit colour and size for free, and one request delivers all of them. The bill comes later: the whole file downloads even when the page shows two icons, the glyphs are invisible until the font arrives, and a screen reader meets a private-use character with no idea what it is.
On phones there is a louder failure. A glyph that the subset does not carry is not missing quietly: the system substitutes something, and an arrow that was a thin line on desktop turns up as a colour emoji.
Reading the font instead of redrawing it
The temptation is to redraw the icons from a library that looks close enough. That is a design change smuggled in as a refactor, and someone will notice the arrow got friendlier.
So the font was read rather than replaced. opentype.js parses it, every glyph in use is looked up by its code point, and its outline comes out as path data with the original dimensions and the original curves.
const font = await opentype.load(legacyFontPath);
const path = font.charToGlyph(char).getPath(0, size, size);
writeComponent(name, path.toPathData(2));Eighteen components that take currentColor
The output is 18 small components, one icon each, each an SVG that fills with currentColor and sizes from its box. They inherit colour and size the way the font did, and they arrive with the markup instead of after it.
The font gave icons the good manners of text. Taking it apart kept the manners and dropped the bill.
What it changed downstream
The font file left the bundle for good, and the icons stopped being a loading state. The rule that came out of it is now house style: no glyph arrows or crosses in copy, because the character you typed is not the one every device will draw.
It also fits the wider diet on that site: three production dependencies in total, and an asset pipeline that took 52.0 MB down to 2.4 MB. An icon font is exactly the sort of thing that hides inside the other 49 MB.
What I would repeat
Extract from the source of truth rather than redraw by eye, generate the components so the extraction can be repeated, and delete the font in the same commit so nobody can quietly keep using it.