In this article
Written & Verified by
Sarah Mitchell
Product Designer, Font Specialist
What is a Font Fallback Chain?
The CSS font-family property accepts a comma-separated list of font names. This list is a fallback chain — an ordered sequence of fonts the browser evaluates left to right. The browser renders each character using the first font in the list that both contains the character and is available on the user's device.
Fallbacks activate in three scenarios: the custom web font fails to download, the font downloads but lacks a specific character (for example, a Greek letter in a Latin-only font), or the font has not yet loaded and the browser falls back to a system font while waiting. Because browsers operate character by character — not word by word — a single line of text can draw glyphs from multiple fonts simultaneously.
/* The browser reads this list left to right */ font-family: 'Inter', /* 1st: preferred custom web font */ 'Helvetica Neue', /* 2nd: similar macOS system font */ Arial, /* 3rd: cross-platform fallback */ sans-serif; /* 4th: generic family */
Without a well-designed fallback chain, a font failure means the browser falls back to its default serif font — Times New Roman on most systems — even if your design calls for a clean sans-serif. The chain is your insurance policy: it controls exactly which font users see when your first choice is unavailable.
System Font Inventory by Operating System
Knowing which fonts are pre-installed on each platform lets you craft accurate fallbacks. The table below lists the primary system fonts across major operating systems for five script categories.
| OS | Serif | Sans-Serif | Monospace | CJK | Arabic / Indic |
|---|---|---|---|---|---|
| macOS / iOS | Georgia, Times New Roman | San Francisco (SF Pro), Helvetica Neue | SF Mono, Menlo, Monaco | Hiragino Sans, PingFang SC/TC, Apple SD Gothic Neo | Geeza Pro (Arabic), Kohinoor Devanagari |
| Windows 11 | Georgia, Times New Roman, Cambria | Segoe UI, Segoe UI Variable, Calibri | Cascadia Code, Consolas, Courier New | Microsoft YaHei (SC), Microsoft JhengHei (TC), Meiryo, Malgun Gothic | Segoe UI Historic (Arabic), Mangal (Devanagari) |
| Android 14 | Noto Serif | Roboto, Roboto Flex | Roboto Mono | Noto Sans CJK SC/TC/JP/KR | Noto Naskh Arabic, Noto Sans Devanagari |
| Linux (Ubuntu) | DejaVu Serif, Liberation Serif | Ubuntu, DejaVu Sans, Liberation Sans | Ubuntu Mono, DejaVu Sans Mono | WenQuanYi Micro Hei, IPAGothic | Lohit Devanagari, Amiri (Arabic) |
Note: San Francisco is not accessible by font name — use -apple-system or system-ui to access it on Apple devices.
Building Effective Fallback Stacks
The goal is to degrade gracefully, maintaining visual similarity at each level. A four-tier approach works for most cases.
Your custom web font — loaded via @font-face
Platform font that closely matches your custom font
A font present everywhere (Arial, Georgia)
Final safety net: sans-serif, serif, monospace
Latin Script Stack (Inter-based)
/* Inter + system fallbacks */ font-family: 'Inter', /* Custom: Google Fonts / self-hosted */ 'Helvetica Neue', /* macOS similarity fallback */ Arial, /* Windows / cross-platform */ sans-serif; /* Generic safety net */
CJK-Ready Stack (Japanese priority)
/* Supports Latin + Japanese + Chinese fallback */ font-family: 'Noto Sans JP', /* Custom CJK web font */ 'Hiragino Sans', /* macOS Japanese system font */ 'Yu Gothic', /* Windows Japanese system font */ 'Meiryo', /* Older Windows Japanese */ 'Microsoft YaHei', /* Windows Chinese — CJK overlap */ sans-serif;
Arabic / RTL Stack
/* Arabic text with system fallbacks */ font-family: 'IBM Plex Arabic', /* Custom Arabic web font */ 'Geeza Pro', /* macOS / iOS system Arabic font */ 'Arabic Typesetting',/* Windows Arabic system font */ 'Noto Naskh Arabic', /* Android / Linux fallback */ sans-serif;
Mixed-Script Stack (global audience)
/* Latin primary, wide script coverage in fallbacks */ font-family: 'Inter', 'Noto Sans', /* covers 1000+ scripts via subset */ 'Hiragino Sans', /* macOS Japanese */ 'Noto Sans CJK SC', /* Android Simplified Chinese */ 'Microsoft YaHei', /* Windows Simplified Chinese */ 'Geeza Pro', /* macOS Arabic */ 'Noto Naskh Arabic', /* Android Arabic */ sans-serif;
CSS Font Metric Override Properties
Every font carries internal metrics that determine how much vertical space it occupies: the ascent (height above the baseline), descent (depth below the baseline), and line gap (extra spacing between lines). When the browser swaps from a fallback font to your web font, differences in these metrics cause elements to shift — contributing to Cumulative Layout Shift (CLS).
CSS provides four @font-face descriptors to override these metrics on a fallback font, forcing it to match the dimensions of your web font:
size-adjust
Scales the entire glyph and metrics of the fallback font by a percentage. If your web font renders slightly smaller than Arial at the same font-size, set size-adjust: 105% to expand Arial to match.
size-adjust: 105%; /* Scale fallback up 5% */ size-adjust: 92%; /* Scale fallback down 8% */
ascent-override
Sets the ascent metric as a percentage of the font-size. The ascent determines how far above the baseline the tallest glyphs reach (capitals, ascenders like 'h' and 'l'). Matching this prevents the first line from jumping vertically on swap.
ascent-override: 90%; /* Most web fonts: 85–100% */
descent-override
Sets the descent metric — how far below the baseline descenders (g, j, p, q, y) extend. This controls the bottom boundary of each line box.
descent-override: 22%; /* Typical range: 15–35% */
line-gap-override
Sets the line gap metric — the recommended extra space between lines built into the font itself (separate from CSS line-height). Most modern web fonts set this to 0, relying on CSS instead.
line-gap-override: 0%; /* Match web fonts with no built-in gap */
Complete Metric-Matched Fallback @font-face
The pattern is to create a new virtual font name that maps to a local system font, then apply all four overrides to match your web font's metrics:
/* Step 1: Your web font */
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: swap;
}
/* Step 2: Metric-matched fallback that mimics Inter's dimensions */
@font-face {
font-family: 'Inter-Fallback';
src: local('Arial'); /* Use system Arial, no download */
size-adjust: 107%; /* Inter is slightly narrower than Arial */
ascent-override: 90%; /* Inter ascent metric */
descent-override: 22.43%; /* Inter descent metric */
line-gap-override: 0%; /* Inter has no built-in line gap */
}
/* Step 3: Reference both in your font stack */
body {
font-family: 'Inter', 'Inter-Fallback', sans-serif;
}How to find exact values: Use the Perfect Font Fallback tool or the next/font package (which computes these values automatically). You can also extract metrics from the font file using tools like fonttools and the formula: metric / unitsPerEm * 100%.
Preventing Cumulative Layout Shift (CLS)
Font-related CLS occurs because different fonts occupy different amounts of space at the same CSS font-size. When the browser renders your page initially with a fallback font and then swaps to the web font, every text element whose dimensions change causes layout shift — elements below the text jump, images reflow, and users lose their scroll position.
What causes the shift
Before (no metric matching)
Fallback font (Arial, 16px) takes 24px of vertical space per line. Web font (Inter, 16px) takes 21px. Result: a 400-word article shrinks by ~12px on font swap, pushing all subsequent content upward.
/* No metric matching — causes CLS */ font-family: 'Inter', Arial, sans-serif;
After (metric-matched fallback)
The Inter-Fallback @font-face overrides Arial's metrics to match Inter exactly. Both occupy 21px per line. Font swap is invisible — no layout shift, CLS score near zero.
/* Metric-matched — zero CLS */ font-family: 'Inter', 'Inter-Fallback', sans-serif;
Calculation approach
To calculate the correct size-adjust value, find the ratio of your web font's x-height to the fallback font's x-height. Then invert it:
/* Formula:
size-adjust = (webFont.xHeight / fallbackFont.xHeight) * 100%
Example: Inter x-height = 0.527em, Arial x-height = 0.495em
size-adjust = (0.527 / 0.495) * 100 = 106.46% ≈ 107%
*/
@font-face {
font-family: 'Inter-Fallback';
src: local('Arial');
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22.43%;
line-gap-override: 0%;
}The next/font module in Next.js 13+ computes and injects these values automatically. The open-source Fontaine package does the same for Vite/Nuxt projects.
Generic Font Families
CSS defines ten generic font families. The browser maps each to the best available installed font on the current platform. These should always be the final entry in your fallback chain — they guarantee some font is always used, even if nothing else in the list is available.
| Generic Family | macOS | Windows | Android | Use Case |
|---|---|---|---|---|
| system-ui | San Francisco (SF Pro) | Segoe UI Variable | Roboto | Native app feel, UI text |
| ui-serif | New York | Cambria | Noto Serif | System serif for reading |
| ui-sans-serif | San Francisco | Segoe UI | Roboto | System sans for body text |
| ui-monospace | SF Mono | Cascadia Code | Roboto Mono | Code blocks, terminals |
| ui-rounded | SF Pro Rounded | (no match) | (no match) | Friendly / playful UI (Apple only) |
| sans-serif | Helvetica | Arial | Roboto | Universal last resort |
| serif | Times New Roman | Times New Roman | Noto Serif | Serif last resort |
| monospace | Courier New | Courier New | Droid Sans Mono | Code, terminal last resort |
| emoji | Apple Color Emoji | Segoe UI Emoji | Noto Color Emoji | Emoji character rendering |
| math | STIX Two Math | Cambria Math | Noto Sans Math | Mathematical notation |
Tip: The difference between system-ui and sans-serif is significant. system-ui maps to the OS UI font (San Francisco, Segoe UI Variable, Roboto), while sans-serif may map to an older system default like Helvetica or Arial. For UI-style designs, prefer system-ui.
Ready-to-Use Font Stacks
These stacks are copy-paste ready. Each covers the most common failure scenarios for its intended use case. Replace the first value with your own custom web font as needed.
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
Industry standard. Covers macOS (-apple-system), Chrome on macOS (BlinkMacSystemFont), Windows (Segoe UI), Android (Roboto), and emoji on all platforms.
font-family: 'Lora', 'Palatino Linotype', 'Book Antiqua', Palatino, Georgia, 'Times New Roman', serif;
Lora as the custom serif, Palatino variants on macOS/Windows, Georgia as the universal fallback, Times New Roman as final serif anchor.
font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', 'Menlo', 'Consolas', 'Liberation Mono', 'Courier New', monospace;
JetBrains Mono and Fira Code as custom options, Cascadia Code for Windows 11, SF Mono/Menlo for macOS, Consolas for older Windows, Liberation Mono for Linux.
/* For Simplified Chinese + Latin sites */ font-family: 'PingFang SC', /* macOS / iOS */ 'Hiragino Sans GB', /* macOS legacy */ 'Microsoft YaHei', /* Windows */ 'Noto Sans SC', /* Android / Linux */ 'WenQuanYi Micro Hei',/* Linux */ sans-serif;
Use :lang(zh-Hans) selector to apply this only to Simplified Chinese text elements, keeping Latin text on your primary stack.
/* For Arabic / RTL sites */ font-family: 'Noto Naskh Arabic', /* Google Fonts, excellent coverage */ 'Cairo', /* Alternative: modern geometric */ 'Geeza Pro', /* macOS / iOS system Arabic */ 'Arabic Typesetting', /* Windows system Arabic */ 'Amiri', /* Linux / serif Arabic fallback */ sans-serif;
Always pair with direction: rtl and text-align: right (or text-align: start with logical properties).
/* Native OS feel, zero load time */ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', sans-serif;
No web font loading at all. Ideal for dashboards, admin UIs, and performance-critical pages where brand font is not required. Zero CLS, zero font load time.
Font Fallback Chains FAQs
Common questions about building robust font-family stacks
Written & Verified by
Sarah Mitchell
Product Designer, Font Specialist
Related Resources
Font Display Swap
Control FOIT and FOUT with font-display values
Font Loading Metrics
LCP, CLS, and Core Web Vitals impact
FOUT / FOIT Problems
Solutions for font flash issues
CSS Generator
Generate @font-face CSS with metric overrides
Multilingual Font Setup
unicode-range and :lang() for multi-script sites
CJK Font Optimization
Reduce CJK fonts from 20MB to under 500KB
Generate Your Font Stack CSS
Use our CSS Generator to build @font-face declarations with size-adjust and metric overrides calculated automatically.
Open CSS Generator