CSS Typography

CSS font stacks: mejores prácticas para fuentes de respaldo

Updated febrero 24, 2026
Crea CSS font stacks a prueba de fallos con respaldos perfectos. Cómo ordenar las fuentes, usar system-ui y evitar el flash de CLS al cargar fuentes web.

CSS Font Stacks: Best Practices for Fallback Fonts

A CSS font stack is the ordered list of typefaces specified in a font-family declaration. The browser works through the list from left to right, using the first font it can find and render. If none of the named fonts are available, it falls back to the final value — always a generic family name like sans-serif, serif, or monospace.

Writing good font stacks is more than listing a few font names. It's about understanding platform differences, how fallback fonts affect layout, how to use modern CSS properties to match fallback metrics, and which recipes to reach for in common design scenarios.


How CSS Font Stacks Work

When a browser encounters font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif, it checks:

  1. Is 'Inter' available? (Downloaded via @font-face, or pre-installed) — Use it
  2. If not: Is 'Helvetica Neue' installed? — Use it
  3. If not: Is 'Arial' installed? — Use it
  4. If not: Use the OS default sans-serif font

The browser evaluates this per character, not per element. If a character in your text doesn't exist in Inter's glyph set (say, a Chinese character), the browser falls back to the next font in the stack that contains that glyph. This makes font stacks a partial per-character fallback system as well.

What "Available" Means

A font is available if: - It was declared with @font-face and the file has been downloaded - It was referenced via local() in an @font-face and is installed on the system - It is a built-in system font

/* This declares Inter as available via download */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/Inter-Variable.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}

/* Now this stack uses the downloaded Inter */
body {
  font-family: 'Inter', system-ui, sans-serif;
}

Generic Families

Always end your stack with a generic family. Never leave a font-family declaration without one.

/* Generic families */
.sans  { font-family: system-ui, sans-serif; }
.serif { font-family: Georgia, serif; }
.mono  { font-family: 'Courier New', monospace; }
.cursive { font-family: cursive; }
.fantasy { font-family: fantasy; }

/* The newest: system-ui, ui-sans-serif, ui-serif, ui-monospace */
.native-ui { font-family: system-ui, -apple-system, sans-serif; }

The System Font Stack (system-ui)

The system font stack tells the browser to use the operating system's default UI font. This produces text that feels native to the user's platform — the same font they see in system menus, dialogs, and native apps.

The Minimal System Stack

body {
  font-family: system-ui, -apple-system, sans-serif;
}

system-ui is the CSS specification keyword for the system UI font. Browser support is excellent across all modern platforms. -apple-system is a legacy alias for older Safari. The final sans-serif is the generic fallback.

What This Resolves To

Platform Font
macOS / iOS SF Pro / San Francisco
Windows 11+ Segoe UI Variable
Windows 10 Segoe UI
Android Roboto
ChromeOS Roboto
Linux Depends on distribution — often Cantarell, Ubuntu, or Noto Sans

The Extended System Stack

Some teams use a longer stack for maximum coverage of older systems:

body {
  font-family:
    system-ui,
    -apple-system,          /* Safari on macOS/iOS < 2019 */
    BlinkMacSystemFont,     /* Chrome on macOS < 2019 */
    'Segoe UI',             /* Windows */
    Roboto,                 /* Android */
    Oxygen,                 /* KDE Linux */
    Ubuntu,                 /* Ubuntu Linux */
    Cantarell,              /* GNOME Linux */
    'Helvetica Neue',       /* macOS/iOS fallback */
    Arial,                  /* Universal fallback */
    sans-serif;             /* Generic */
}

This extended stack is what GitHub famously used before simplifying to system-ui. For most modern projects, the shorter version is sufficient.

When to Use the System Stack

Use system-ui when: - Building developer tools, dashboards, or admin interfaces - Performance is the top priority and custom fonts aren't worth the overhead - You want a native app aesthetic - The UI is a means to an end, not a brand expression

Use a custom font stack when: - Brand typography is important - The reading experience requires a specific typeface (long-form content) - You need consistent cross-platform appearance


Building Custom Stacks: Web Font + Fallbacks

When you use a custom web font, you need fallbacks that activate while the font loads and for users where the font fails to load.

Matching Fallback to the Web Font

The ideal fallback resembles your web font in category, proportion, and weight. A good fallback minimizes the visual jump when the web font swaps in.

/* Inter → system-ui → Helvetica Neue → Arial */
body {
  font-family: 'Inter', system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
}

/* Source Serif 4 → Georgia → Times New Roman */
.article-body {
  font-family: 'Source Serif 4', Georgia, 'Times New Roman', serif;
}

/* Lora → Palatino (wider, old-style serif) */
blockquote {
  font-family: 'Lora', Palatino, 'Book Antiqua', Georgia, serif;
}

/* Playfair Display → Didot (similar high-contrast display serif) */
.display-heading {
  font-family: 'Playfair Display', Didot, 'Palatino Linotype', serif;
}

/* JetBrains Mono → Menlo → Consolas → monospace */
code {
  font-family: 'JetBrains Mono', Menlo, Consolas, 'Courier New', monospace;
}

Platform-Aware Fallback Chaining

Different platforms have different pre-installed fonts. A well-crafted stack handles each:

/* Heading stack: Playfair Display → platform serif alternates */
h1, h2, h3 {
  font-family:
    'Playfair Display',       /* Web font */
    'Palatino Linotype',      /* Windows */
    Palatino,                 /* macOS */
    'Book Antiqua',           /* Older Windows */
    Georgia,                  /* Universal serif fallback */
    serif;
}

/* Sans-serif body: Roboto → platform sans */
body {
  font-family:
    'Roboto',                 /* Web font */
    'Helvetica Neue',         /* macOS + iOS older */
    Helvetica,                /* macOS + legacy */
    Arial,                    /* Windows + universal */
    sans-serif;
}

size-adjust: Matching Fallback Metrics

The size-adjust descriptor in @font-face is a game-changer for reducing layout shift when fonts swap. It lets you scale a fallback font to approximately match the dimensions of the web font.

When fonts have different x-heights, cap heights, and character widths, swapping from fallback to web font causes content to reflow — paragraphs shift, buttons resize, headings reflux. size-adjust lets you compensate by scaling the fallback.

How size-adjust Works

/* Create a modified version of Arial that matches Inter's metrics */
@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial');         /* Use Arial from the system */
  size-adjust: 107%;           /* Scale up to match Inter's width */
  ascent-override: 90%;        /* Match Inter's ascent */
  descent-override: 22%;       /* Match Inter's descent */
  line-gap-override: 0%;       /* Match Inter's line gap */
}

/* Web font */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/Inter-Variable.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}

/* Stack: Inter → adjusted Arial fallback → system sans */
body {
  font-family: 'Inter', 'Inter Fallback', system-ui, sans-serif;
}

When the page first loads, Inter Fallback (the adjusted Arial) renders. When Inter finishes loading and swaps in, the layout change is minimal because the metrics have been compensated.

Finding the Right Values

The exact values depend on the specific fonts being compared. You can find them by:

  1. Computed experimentally: Render the same text in both fonts at the same size and measure the difference
  2. Using a tool: The Font Style Matcher and Malte Ubl's Automatic Font Matching calculate these values
/* Roboto → Roboto fallback using adjusted Arial */
@font-face {
  font-family: 'Roboto Fallback';
  src: local('Arial');
  size-adjust: 100%;
  ascent-override: 92.7189%;
  descent-override: 24.4099%;
  line-gap-override: 0%;
}

/* Lora → Lora fallback using adjusted Georgia */
@font-face {
  font-family: 'Lora Fallback';
  src: local('Georgia');
  size-adjust: 104%;
  ascent-override: 87%;
  descent-override: 23%;
  line-gap-override: 0%;
}

The Resulting Font Stacks

body {
  font-family: 'Roboto', 'Roboto Fallback', sans-serif;
}

.serif-body {
  font-family: 'Lora', 'Lora Fallback', serif;
}

This approach produces near-zero Cumulative Layout Shift (CLS) from font swapping — a Core Web Vital metric that Google uses for search ranking. If your CLS is impacted by font loading, size-adjust is your most effective tool.


Platform-Specific Considerations

macOS and iOS

macOS ships with a small set of pre-installed fonts: - Sans-serif: Helvetica Neue, Helvetica, Arial, system-ui (San Francisco) - Serif: Georgia, Times New Roman, Palatino - Mono: Menlo, Courier New - Notable extras: Didot, Optima, Gill Sans, Futura (on macOS)

macOS has long had subpixel antialiasing for fonts. Starting with macOS Mojave, Apple disabled it across the OS. -webkit-font-smoothing: antialiased can still affect rendering — see the font smoothing guide for details.

Windows

Windows 11 ships with a richer set of fonts than previous versions: - Sans-serif: Segoe UI Variable, Arial, Calibri, Tahoma, Verdana, Trebuchet MS - Serif: Georgia, Times New Roman, Cambria, Palatino Linotype - Mono: Consolas, Courier New, Cascadia Code (in newer builds)

Verdana and Georgia were designed specifically for screen readability and have unusually wide character widths — keep this in mind when using them as fallbacks.

Android

Android ships with Roboto as its primary system font across the standard interface. Noto (for international character coverage) is also bundled. Most Android browsers ship their own font fallback behavior.

/* A robust cross-platform body stack */
body {
  font-family:
    'Inter',
    'Inter Fallback',   /* Adjusted fallback */
    system-ui,
    -apple-system,
    'Segoe UI',
    Roboto,
    Arial,
    sans-serif;
}

Common Font Stack Recipes

Recipe 1: Clean Modern Sans (Tech / Startup)

:root {
  --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

Inter or system UI fallback. Clean, readable, neutral. Works at every size.

Recipe 2: Humanist Sans (Agency / Creative)

:root {
  --font-sans: 'Source Sans 3', 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
}

Warm humanist feel. Gill Sans as a fallback (widely installed on macOS).

Recipe 3: Geometric Display (Brand Headings)

:root {
  --font-display: 'Raleway', 'Futura', 'Century Gothic', 'Trebuchet MS', sans-serif;
}

Futura is pre-installed on macOS. Good for geometric display headings.

Recipe 4: Scholarly Serif (Editorial / Blog)

:root {
  --font-serif: 'Lora', 'Palatino Linotype', Palatino, Georgia, 'Times New Roman', serif;
}

Palatino as a platform fallback gives a refined, humanist feel. Georgia as the universal backup.

Recipe 5: Monospace Code

:root {
  --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', Menlo, Consolas, 'Courier New', monospace;
}

JetBrains Mono and Fira Code for ligature support. Menlo on macOS, Consolas on Windows, Courier New as the universal fallback.

Recipe 6: Pure System UI (Performance First)

:root {
  --font-system: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
                 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans',
                 sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
                 'Segoe UI Symbol', 'Noto Color Emoji';
}

This is Tailwind CSS's default font stack — highly compatible, zero downloads, native feel. Emoji-capable via the trailing emoji font entries.

:root {
  --font-serif: 'Source Serif 4', 'Cambria', Georgia, 'Times New Roman', Times, serif;
}

Source Serif 4 has excellent OpenType features and optical sizing. Cambria is a well-designed screen serif on Windows.

/* Apply recipes across component types */
body {
  font-family: var(--font-sans);
}

.prose, article, .blog-post {
  font-family: var(--font-serif);
}

code, pre, kbd {
  font-family: var(--font-mono);
}

.hero-headline {
  font-family: var(--font-display);
}

A well-constructed font stack is an act of defensive design. Your web font is the intention; your fallbacks are the guarantee that the experience remains good for every user, on every device, at every connection speed.

Typography Terms

Try These Tools

Fonts Mentioned

Related Articles