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.

Fonts selected by the system stack per platform A matrix of platforms and resolved fonts. macOS and iOS resolve the sans stack to San Francisco and monospace to SF Mono. Windows 11 resolves sans to Segoe UI Variable and monospace to Cascadia Code or Consolas. Android and ChromeOS resolve sans to Roboto and monospace to Roboto Mono or Droid Sans Mono. Ubuntu resolves sans to Ubuntu and monospace to Ubuntu Mono or DejaVu Sans Mono. What the stack resolves to on each platform Platform Sans (body) Mono (code) macOS / iOS San Francisco SF Mono Windows 11 Segoe UI Variable Cascadia Code / Consolas Android / ChromeOS Roboto Roboto Mono / Droid Sans Mono Ubuntu Linux Ubuntu Ubuntu Mono / DejaVu Sans Mono
Checked with DevTools' rendered fonts panel on each platform.

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:

ItemBefore
Font files on a first visit6 files, 104 KB
Preloads competing with the LCP resource2
Font swap shift (field, with font-display: swap)0.04 at p75
Time until final fonts rendered, slow 4Gabout 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: 70ch rather than a pixel width; ch adapts 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.

Font bytes and requests before and after switching to system fonts Paired bars. Font bytes on a first visit fell from 104 kilobytes to 0 on documentation pages and to 18 kilobytes on the home page, which kept one optional display font for the hero heading. Font requests fell from 6 to 0 on documentation pages. Font cost on a first visit Web fonts System stacks Docs page font bytes 104 KB 0 KB Home page font bytes 104 KB 18 KB
Brotli-compressed WOFF2 bytes from the Lighthouse network table.

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:

MeasureInter + JetBrains MonoSystem stacks
Font bytes, first visit104 KB0 KB
Requests before first render4 (HTML, CSS, 2 font preloads)2 (HTML, CSS)
LCP p751.62 s1.44 s
CLS p750.050.01
FCP p751.21 s1.09 s
Reader complaints about typography—0 in 3 months
Mobile LCP before and after removing web fonts Vertical bars of mobile field LCP at the 75th percentile. With Inter and JetBrains Mono web fonts, 1.62 seconds. With system font stacks, 1.44 seconds. Field LCP at p75 on mobile 1.62 s Web fonts 1.44 s System stacks
Two weeks of RUM on documentation pages; traffic mix was comparable.

Pitfalls & Rollback

  • Relying on system-ui alone. 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-face rules 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-family values and @font-face rules 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.

Filed underHow-tos