HTML font family list

font-family takes a comma separated list and uses the first name the device actually has. The last entry must be a generic keyword, because that one always resolves.

An HTML font family list is the comma separated value of font-family, and the browser uses the first name on it that the device actually has.

body {
  font-family: "Segoe UI", Roboto, Arial, sans-serif;
}

The list is a fallback chain, not a preference blend. Reading stops at the first match.

A page with three paragraphs, each using a different font-family stack.
A page with three paragraphs, each using a different font-family stack.

The one rule that cannot be broken

The last entry must be a generic keyword. There are five in common use.

Generic Resolves to Use for
sans-serif The device's default sans Interface text, most body copy
serif The device's default serif Long reading, print-like documents
monospace The device's fixed-width font Code, tables of figures
system-ui The interface font itself Matching the host operating system
ui-monospace The interface fixed-width font Code in interface chrome

A generic always resolves, because the browser guarantees a mapping. Without one at the end, a device missing every named font falls back to whatever the user set, which can be anything.

Ready-made stacks

System interface text. Matches the device, downloads nothing.

font-family:
  -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
  "Helvetica Neue", Arial, "Noto Sans", sans-serif;

Reading serif. For reports and long documents.

font-family: Charter, Georgia, Cambria, "Times New Roman", Times, serif;

Monospace for code and figures.

font-family:
  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
  "Liberation Mono", monospace;

Each list works because the names are ordered from most specific to most widely available. The final generic catches everything left.

Quoting rules

  • Quote names with spaces: "Times New Roman", "Segoe UI", "Helvetica Neue".
  • Quote names beginning with a digit or containing punctuation.
  • Do not quote generic keywords. "sans-serif" in quotes is read as a family literally named that, which no device has.
  • Single-word names are fine either way. Georgia and "Georgia" both work.

A single bad quote invalidates the whole declaration, and the element falls back to its inherited font with no error shown.

Per-character fallback

The chain applies glyph by glyph, not once for the whole page. A paragraph in Georgia with a Korean word in it uses Georgia for the Latin letters and the next matching family for the Korean.

That is why a list ending in "Noto Sans", sans-serif covers more scripts than one ending in Arial, sans-serif. Add a broad-coverage family before the generic when the content is multilingual.

A paragraph mixing Latin and non-Latin text, showing two families in one line.
A paragraph mixing Latin and non-Latin text, showing two families in one line.

Applying the list without repeating it

Set it once on :root or body and let inheritance carry it. Override only where the font genuinely changes.

:root {
  --font-ui: -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-mono: ui-monospace, Menlo, Consolas, monospace;
}
body { font-family: var(--font-ui); }
code, pre { font-family: var(--font-mono); }

Custom properties keep the long stack in one place. Changing the brand face later becomes a one-line edit.

Building a list that holds up

Order the names from most specific to most available, and stop at four or five.

  1. Your preferred face, if you have one and it is either installed or loaded.
  2. The platform equivalents. "Segoe UI" for Windows, -apple-system for Apple devices, Roboto for Android.
  3. A broadly installed fallback. Arial or Helvetica for sans, Georgia or "Times New Roman" for serif.
  4. A wide-coverage family when the content is multilingual, such as "Noto Sans".
  5. The generic keyword.

Longer lists do not help. Every name after the first that resolves is dead weight, and each one is a chance to introduce a typo that invalidates the declaration.

Metrics differ between fallbacks

Two fonts at the same font-size are rarely the same visual size. Georgia at 16px reads noticeably larger than Times New Roman at 16px, because the x-height differs.

That matters when a fallback is likely to be used. A layout tuned to the first name in the list can break when the second one loads instead.

Adjustment Effect
size-adjust in @font-face Scales the fallback to match the primary
ascent-override Aligns the line box height
line-height in unitless form Scales with whichever font resolved

A unitless line-height: 1.6 is the low-effort version of this. It scales with the resolved font size rather than freezing at a pixel value tuned to one face.

Weights and the list

A stack can resolve the family and still miss the weight. If font-weight: 600 is requested and the resolved family has only 400 and 700, the browser synthesises a bolder version, which usually looks worse than 700.

h2 { font-weight: 700; }        /* safe on system stacks */
.lead { font-weight: 400; }     /* rather than 350 or 450 */

On a system stack, stay on 400, 600 and 700. Intermediate weights are worth requesting only when you control the loaded file.

When a font-family list is the wrong tool

If the page must use one exact typeface, a list cannot guarantee it. That needs a loaded web font, which brings a file the page depends on.

For an HTML file you intend to send, that dependency matters. A font referenced by a folder path does not travel, which is the usual cause of fonts not loading on someone else's machine.

Checking what actually rendered

The font test page opened from a share link on a different device.
The font test page opened from a share link on a different device.

Your machine has fonts other people's do not. A stack that looks right locally can resolve to a different family for a reader.

Open the file in the HTML file opener first, since it has never seen your project. Then paste the HTML into a document and share it as a link, so a colleague on another operating system can confirm what they see.

Because a system stack loads nothing, the page stays self-contained and renders the same whether it is opened from a file or from an address.

Next: how to change the font in HTML for the markup side, and HTML font color for the other half of type styling.

Questions people ask

How does a font-family list decide which font to use?

The browser reads the list left to right and uses the first family that is installed or loaded. This happens per character, so a name later in the list can supply a glyph the earlier one lacks. The final generic keyword is the guaranteed fallback.

Which font names need quotation marks?

Any name containing spaces, digits at the start, or punctuation. "Times New Roman" and "Helvetica Neue" need quotes. Single words like Georgia and Arial do not, though quoting them is harmless. Generic keywords such as sans-serif must never be quoted.

What is the system font stack?

A list that names each platform's interface font so the page matches the device. A common form is -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif. It loads nothing, so there is no download and no flash of unstyled text.

Do I need a web font instead of a list?

Only when the exact typeface matters, for example a brand face. A web font adds a network request and a file the page depends on, which is a problem for a file you send around. A system stack keeps the page self-contained.

Keep reading