Skip to content
fontstay.dev
Source code on GitHub

Guide

A short explanation of what the generated CSS does and why it prevents the text from jumping when your web font arrives.

Why fonts shift the layout

While a web font loads, the browser draws the text in a fallback font. When the web font arrives the text is redrawn: if the glyphs are wider or the lines taller, lines wrap differently and everything below moves. Google measures this as Cumulative Layout Shift (CLS): 0.1 or less is good, above 0.25 is poor. Making the fallback font match the metrics of the web font keeps the lines where they are.

The @font-face descriptors we generate

Each fallback is a local() system font declared with descriptors that rescale it: size-adjust scales the glyphs so the text has the same width, and ascent-override, descent-override and line-gap-override set the vertical metrics so the lines have the same height. The font-family stack lists the web font first, then the adjusted fallbacks, then a generic family.

@font-face {
  font-family: "Inter Fallback Arial";
  src: local("Arial");
  size-adjust: 107.12%;
  ascent-override: 90.44%;
  descent-override: 22.52%;
  line-gap-override: 0%;
  unicode-range: U+20-7E, U+A0-FF;
}

body {
  font-family: "Inter", "Inter Fallback Arial", sans-serif;
}
First browser version that supports each feature (MDN browser-compat-data 8.1.5)
DescriptorChromeEdgeFirefoxSafari
size-adjust92929217
ascent-override878789—
descent-override878789—
line-gap-override878789—
font-size-adjust127127316.4
unicode-range112363.1

— means not supported, ? means unknown. Browsers that lack a descriptor simply ignore it, so the CSS is safe everywhere.

Safari and the vertical overrides

Safari supports size-adjust (since 17) but not ascent-override, descent-override or line-gap-override. For those browsers the generator adds font-size-adjust, which matches the x-height of the web font, and a fixed line-height, which makes the line box independent of the fallback metrics.

unicode-range

A face with a unicode-range is used only for the listed code points. Limiting the adjusted fallbacks to the characters the web font covers keeps the adjustment from applying to glyphs the web font will never draw. Ranges are compacted without loss (adjacent code points are merged) and match the subsets used by Google Fonts.

Font formats

Use WOFF2 for the web: it is the smallest and every current browser supports it. WOFF, TrueType (TTF) and OpenType (OTF) files also work with @font-face. Font collections (TTC, OTC) cannot be used directly in a browser, so this tool splits them into separate fonts.

Font licenses

A font file is software and its license decides whether you may put it on a website. The generated CSS only references fonts already installed on the visitor’s system (local()), but the web font you serve must be licensed for it:

The license text and URL are in the font’s name table (name IDs 13 and 14) and the embedding permissions are in the OS/2 table (fsType). Always read the license from the font’s source as well.

Specifications