Using System Font Stacks to Skip Web Fonts
Every font-loading optimization — preloading, subsetting, font-display, metric-matched fallbacks — exists to reduce the cost of downloading fonts. The option that removes the cost entirely is not downloading any. Every reader's device already has a high-quality interface font: San Francisco on Apple platforms, Segoe UI Variable on Windows, Roboto on Android and ChromeOS, and Cantarell, Ubuntu or Noto on Linux. A system font stack names them in order, and the browser uses whichever the reader has, with no request, no swap and no layout shift.
This guide replaces two web font families on a 1,300-page Eleventy documentation site with system font stacks for body text, headings and code, covers the choices for monospace and CJK text, discusses what the brand loses and how to keep some identity, and measures the effect. It is part of Font Loading Strategies for Static Sites.
Prerequisites
- An inventory of the web fonts in use: families, weights, styles and where each is used. See Auditing Font Payload per Page.
- Agreement from whoever owns the brand that body text may use platform fonts.
- Screenshot testing on at least macOS, Windows, Android and one Linux distribution.
The Stacks
Three stacks cover most sites:
:root {
--font-sans: system-ui, -apple-system, 'Segoe UI Variable Text', 'Segoe UI', Roboto, 'Noto Sans',
Ubuntu, Cantarell, 'Helvetica Neue', Arial, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji';
--font-mono: ui-monospace, 'SF Mono', 'Cascadia Code', 'Segoe UI Mono', 'Roboto Mono',
Menlo, Consolas, 'Liberation Mono', monospace;
--font-serif: ui-serif, 'New York', 'Iowan Old Style', Georgia, 'Noto Serif', serif;
}
body { font-family: var(--font-sans); }
code, pre, kbd { font-family: var(--font-mono); }
system-ui resolves to the platform interface font in every current browser; the named fonts after it are fallbacks for older browsers and for platforms where system-ui maps poorly. ui-monospace gives SF Mono on Apple devices; Cascadia Code is present on current Windows 11 installations; Consolas and Menlo cover older systems. Emoji fonts are listed last so emoji render in colour rather than from a text font's monochrome glyphs.
What Was Removed
The site had used Inter for body and headings (four weights, Latin and Latin Extended subsets) and JetBrains Mono for code (two weights). Even after subsetting and preloading, those fonts cost:
| Item | Before |
|---|---|
| Font files on a first visit | 6 files, 104 KB |
| Preloads competing with the LCP resource | 2 |
Font swap shift (field, with font-display: swap) | 0.04 at p75 |
| Time until final fonts rendered, slow 4G | about 1.6 s |
The metric-matched fallbacks described in Metric-Matched Fallback Fonts with size-adjust had reduced the swap shift but not removed it: headings with tight letter spacing still reflowed on some viewports.
Typography Adjustments
System fonts differ from each other and from Inter in width and x-height, so a few settings need care:
- Line length. Use
max-width: 70chrather than a pixel width;chadapts to the font's actual width on each platform. - Weights. Segoe UI Variable, San Francisco and Roboto all support 400, 500, 600 and 700, but some Linux fonts lack 500 and 600; design with 400 and 700 where it matters, and let intermediate weights fall back gracefully.
- Letter spacing. Remove tight tracking tuned for Inter on headings; San Francisco and Segoe UI already adjust tracking by size with optical sizing.
font-feature-settings. Features such as tabular numbers (font-variant-numeric: tabular-nums) work in all the major system fonts and are worth keeping for tables.
After adjusting, screenshots of 12 key templates on four platforms were compared for layout breaks — overflowing buttons, wrapped navigation labels — and two fixes were needed, both navigation items that wrapped on Windows at one breakpoint.
Keeping Some Brand Identity
The objection from the design team was brand: Inter was part of the visual identity. The compromise kept one web font for the logo wordmark only — converted to an inline SVG, so it is not a font at all — and for the home page hero heading, loaded with font-display: optional so it is used only when already cached or fast, and never causes a swap. Everywhere else, the platform font. The resulting look is closer to the operating system the reader uses every day, which several readers mentioned positively in feedback on the documentation.
CJK, Arabic and Other Scripts
System stacks shine for non-Latin scripts. A web font covering Japanese or Chinese is several megabytes even when subset; system fonts (Hiragino and Yu Gothic on Apple and Windows, Noto Sans CJK on Android and Linux) are already installed. Add script-specific families for pages in those languages so the right regional variant is used:
:lang(ja) { font-family: system-ui, 'Hiragino Sans', 'Yu Gothic UI', 'Noto Sans JP', sans-serif; }
:lang(zh-Hans) { font-family: system-ui, 'PingFang SC', 'Microsoft YaHei UI', 'Noto Sans SC', sans-serif; }
:lang(ar) { font-family: system-ui, 'SF Arabic', 'Segoe UI', 'Noto Sans Arabic', sans-serif; }
The lang attribute on each page selects the rule; multilingual setups are covered in Internationalization for Static Sites.
When a Web Font Is Still Worth It
System stacks are not the right answer for every site. A publication whose identity is its typography, a brand with a licensed typeface central to its recognition, or a design that depends on a specific display face for headlines will reasonably keep web fonts. The useful question is where the font earns its bytes. On this site the answer was the logo and one hero heading; on a magazine it might be every headline but not body text, which could still use a system serif stack such as ui-serif, Georgia, serif. Splitting the decision by role — headings, body, code, UI chrome — usually finds that at least body text and code can use the platform fonts, which removes the largest and most frequently used files while keeping the brand where readers notice it.
A related middle ground is to keep the brand font but load it only on marketing templates, while documentation and blog templates use system stacks. Readers deep in documentation care about fast, legible text; the landing page is where brand typography does its work.
Measured Impact
Field data from web-vitals RUM, two weeks before and after, mobile documentation pages:
| Measure | Inter + JetBrains Mono | System stacks |
|---|---|---|
| Font bytes, first visit | 104 KB | 0 KB |
| Requests before first render | 4 (HTML, CSS, 2 font preloads) | 2 (HTML, CSS) |
| LCP p75 | 1.62 s | 1.44 s |
| CLS p75 | 0.05 | 0.01 |
| FCP p75 | 1.21 s | 1.09 s |
| Reader complaints about typography | — | 0 in 3 months |
Pitfalls & Rollback
- Relying on
system-uialone. Some locale and platform combinations resolve it badly; keep named fallbacks. - Assuming identical metrics everywhere. Test layouts on each platform; widths differ.
- Designing with weights that do not exist. Some Linux fonts lack 500 and 600.
- Leaving
@font-facerules behind. Unused declarations can still trigger downloads if a family name matches. - Rollback: the change is a few CSS custom properties; restoring the previous
font-familyvalues and@font-facerules brings the web fonts back.
Conclusion
The fastest web font is the one you do not load. System font stacks give every reader a high-quality, familiar interface font with no bytes, no preloads and no swap, and they handle non-Latin scripts better than any web font budget allows. Keep a brand font for the logo or a hero heading if needed, loaded with font-display: optional, and let the platform set everything else. On this site that removed 104 KB and a source of layout shift, and moved field LCP by 180 ms.
FAQ
What is a system font stack?
A font-family list that names the default interface fonts of each operating system, such as system-ui, -apple-system, Segoe UI, Roboto and Noto Sans, so every reader gets their platform's native font without downloading anything.
Do system fonts look unprofessional?
Not today. San Francisco, Segoe UI Variable, Roboto and Cantarell are carefully designed, highly legible interface fonts with wide weight ranges. Many large product and documentation sites use them. The trade-off is that the site looks slightly different on each platform and loses a distinctive brand typeface.
Is system-ui safe to use on its own?
Mostly. system-ui is supported in all current browsers, but on some Linux and Windows configurations with unusual locales it can resolve to a font with poor Latin glyphs. Listing explicit fonts after it and ending with sans-serif guards against that.
How much faster is a site without web fonts?
On the documentation site measured here, removing two web font families saved 104 KB, removed two preloads that competed with the LCP resource, eliminated font-swap layout shift, and improved field LCP at p75 by 180 milliseconds on mobile.
Related
- Parent: Font Loading Strategies for Static Sites — the full font toolbox.
- Font Display: optional vs swap — for the one font you keep.
- Eliminating Layout Shift from Web Fonts — the shift this removes.
- Variable Fonts vs Static Weights — if you keep web fonts.
- Right-to-Left Layouts on Static Sites — system fonts for Arabic.
Filed underHow-tos