@font-face Generator

Write production @font-face CSS for your web fonts – every weight and style, with font-display, variable ranges, optional unicode-range subsetting and a matching preload hint.

Faces

Generated CSS

How to use this tool

  1. Name the family. This is the name you will use in font-family, and it does not have to match the file name.
  2. Set the path to wherever the files are served from – /fonts, a CDN URL, whatever your build produces.
  3. Add one face per file. Regular and bold are filled in as an example; add italic or other weights as needed.
  4. Tick "Variable" for a variable font and give it a weight range instead of a single weight.
  5. Copy the CSS into your stylesheet, and the preload tag into your <head>.

Why there is only WOFF2 in the output

Because that is all you need. WOFF2 has been supported by every current browser since about 2016. The familiar four-format stack – EOT, TTF, WOFF, SVG – is Internet Explorer scaffolding, and browsers take the first format they understand, so the extra src entries are dead weight in every stylesheet carrying them.

If your analytics genuinely show old browsers, add a WOFF entry after the WOFF2 one. For most sites that is a line of CSS solving a problem they do not have.

Choosing font-display

  • swap – the fallback shows immediately and is replaced when the font arrives. Text is never invisible. The right default for body copy.
  • optional – the browser may skip the font entirely on a slow connection. Best when the web font is a nicety rather than the brand.
  • fallback – a very short invisible period, then a short swap window. A compromise if the layout shift from swapping bothers you.
  • block – hides the text for up to three seconds. Almost always the wrong choice; it is what makes pages appear blank on bad connections.
  • auto – leaves it to the browser, which in practice behaves much like block.

What unicode-range actually does

It tells the browser which characters a file covers. If nothing on the page uses those characters, the file is never downloaded. That is how a multilingual family can declare a dozen faces and still cost one download on an English page.

It only pays off if your font files are already split along those lines. If you have one file containing every script, declaring a Latin range on it does not make it smaller — the browser still fetches the whole file. Splitting the file is a subsetting job, which this tool does not do.

About the preload tag

The generated tag preloads only the first face. That is deliberate. Preloading every weight is a common and expensive mistake: it makes the browser fetch fonts the page may never use, competing for bandwidth with the CSS that decides whether it will. Preload the one face in your first paint, and let the rest load normally.

The crossorigin attribute is required even for fonts on your own domain. Fonts are always fetched in anonymous CORS mode, so a preload without it is treated as a different request and the file is downloaded twice.

Need the files first? TTF to WOFF2 and OTF to WOFF2 convert them in your browser, the font analyzer tells you which weights and axes a file actually contains, and the typography scale generator builds the sizes to set them at.

Frequently asked questions

Because that is all a modern site needs. WOFF2 has been supported by every current browser since about 2016. The familiar EOT/TTF/WOFF/SVG stack is Internet Explorer scaffolding, and since browsers use the first format they understand, the extra src entries are dead weight.

swap for body text: the fallback shows immediately and is replaced when the font arrives, so text is never invisible. optional if the web font is a nicety rather than the brand. Avoid block, which can hide your text for up to three seconds on a slow connection.

It tells the browser which characters a file covers, so a file is never downloaded if the page uses none of them. It only saves anything if your font files are already split along those lines - declaring a Latin range on one file containing every script does not make that file smaller.

Because fonts are always fetched in anonymous CORS mode, even from your own domain. A preload without crossorigin is treated as a different request from the real one, so the browser downloads the font twice and the preload actively costs you time.

Preloading every weight is a common and expensive mistake - it makes the browser fetch fonts the page may never use, competing with the CSS that decides whether it will. Preload the one face in your first paint and let the rest load normally.

Tick Variable on the face and give it a weight range instead of a single weight. That produces font-weight: 100 900, which tells the browser the one file covers the whole range so it does not synthesise bold.

Anywhere your server can serve them from - the path field just has to match. Serve them from your own domain where you can, with a long cache header, since a font on a third-party host costs an extra connection before any text can render.