CSS Fonts and font-family: Font Stacks, Weights and System Fonts
CSS Fonts and font-family: Font Stacks, Weights and System Fonts
The CSS font-family property chooses the typeface for text. Because you never know which fonts a visitor has installed, CSS uses a font stack: an ordered list of fallbacks ending with a generic family. This lesson covers font stacks, generic families, system fonts, font-size, weight, style, the font shorthand and how to avoid layout shift from fallback fonts.
What You Will Learn
- How
font-familyand font stacks work - Generic families:
serif,sans-serif,monospace,system-uiand more - A modern system font stack
font-size,font-weight,font-styleandfont-variant- The
fontshorthand and its required order - Choosing readable fonts and pairing them
- Reducing layout shift with fallback font tuning
How font-family Works
The browser goes through the list from left to right and uses the first font that is installed (or loaded) and contains the glyph it needs. It can even pick a different font per character, so a missing Urdu or emoji glyph falls through to the next family.
body {
font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif;
}- Font names with spaces or special characters must be quoted:
'Times New Roman'. - Single-word names like
Arialneed no quotes. - Always end the list with a generic family, which is never quoted.
Generic Font Families
serif: letters with small strokes (serifs). Good for long reading and a traditional feel.sans-serif: clean strokes without serifs. Common for UI and screens.monospace: every character has the same width. Used for code.cursiveandfantasy: decorative styles, inconsistent across systems, rarely recommended.system-ui: the operating system default UI font (San Francisco on Apple devices, Segoe UI on Windows, Roboto on Android).ui-serif,ui-sans-serif,ui-monospace,ui-rounded: system-specific variants, supported mainly in Safari and some other browsers.
A Modern System Font Stack
System fonts load instantly (zero network requests) and feel native on each device:
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
Web Safe Fonts
Fonts that exist on almost every device include Arial, Helvetica, Times New Roman, Georgia, Verdana, Tahoma, Trebuchet MS and Courier New. Availability varies by platform, so always provide fallbacks. For a wider choice and consistent branding, use web fonts (next lesson).
font-size
- Use
remso text respects the user browser settings. - Body text should be at least 16px (
1rem). - Keywords like
small,mediumandlargeexist, but rem values are more precise. - Use
clamp()for fluid headings:font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3.5rem);. - Form inputs below 16px make iOS Safari zoom in on focus, so keep input text at 16px or larger.
font-weight
Keywords: normal (400) and bold (700). Numeric values from 100 to 900 (and any number from 1 to 1000 with variable fonts) select the matching face. lighter and bolder are relative to the parent. If a weight is not available in the font files you loaded, the browser picks the nearest one or fakes bold, which often looks poor.
font-style
normal, italic (uses the true italic design if the font has one) and oblique (slanted version of the upright, optionally with an angle such as oblique 10deg). Use font-synthesis: none to stop the browser from faking bold or italic when real faces are missing.
font-variant and Advanced Features
font-variant-numeric: tabular-nums;makes all digits equal width, ideal for tables and prices.oldstyle-nums,lining-numsandslashed-zeroare also available.font-variant-caps: small-caps;gives true small capitals if the font supports them.font-variant-ligaturesandfont-kerningcontrol ligatures and kerning.font-feature-settingsis the low-level way to toggle OpenType features. Prefer the high-levelfont-variant-*properties when possible.
The font Shorthand
font: italic small-caps 700 1rem/1.5 'Georgia', serif; /* style variant weight size/line-height family */
Only font-size and font-family are required, and they must appear in that order at the end. The shorthand resets any omitted sub-properties (such as line-height) to their defaults, which is a common source of bugs. Many teams prefer longhand properties for clarity.
font-size-adjust
Different fonts have different x-heights, so a fallback font at the same font-size can look much bigger or smaller. font-size-adjust: 0.5; (or from-font) keeps the lowercase letter height consistent between primary and fallback fonts.
Choosing and Pairing Fonts
- Use at most two font families (one for headings, one for body) to keep pages fast and consistent.
- Pair fonts with clear contrast, such as a serif heading with a sans-serif body.
- Prefer fonts with good support for your languages. For Urdu and Arabic script consider Noto Nastaliq Urdu or Noto Naskh Arabic, and always include a generic fallback.
- Test legibility at small sizes and on low-resolution screens.
Reducing Layout Shift from Fallback Fonts
When a web font loads late, text can jump because the fallback has different metrics. Choose a fallback with similar proportions, use font-size-adjust, or tune a local fallback with @font-face descriptors size-adjust, ascent-override, descent-override and line-gap-override (see the Web Fonts lesson).
Common Mistakes
- Forgetting a generic family at the end of the stack.
- Quoting generic names, for example
'sans-serif', which turns them into a font name. - Using the
fontshorthand and accidentally resetting line-height. - Loading many weights and styles that are never used.
- Setting body text in px, which ignores user preferences.
- Relying on
cursiveorfantasyand getting very different results per device.
Frequently Asked Questions
What is a font stack?
It is the comma-separated list in font-family. The browser uses the first available font and falls back down the list.
What is the best font-family for body text?
A well-tested sans-serif or serif web font, or the system font stack for speed. Whatever you choose, use 16px or larger with line-height around 1.6.
Why is my font not changing?
Common causes: a typo in the name, the font is not installed or loaded, a more specific rule overrides it, or you forgot quotes around a name with spaces.
Do I need to quote font names?
Only if the name contains spaces, digits at the start or special characters. Quoting is harmless for any custom name, but never quote generic families.
Key Takeaways
- A font stack ends with a generic family such as
sans-serif. - System font stacks are fast and native looking.
- Use rem for size, numeric values for weight and
tabular-numsfor number tables. - The
fontshorthand resets omitted properties, so use it carefully. - Limit font families and weights for better performance and consistency.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Give the body a font stack that starts with the system UI font, then 'Segoe UI', Roboto and Arial, and ends with the generic sans-serif family. Give the code element a monospace stack that starts with ui-monospace and ends with the generic monospace family.
Press Run to execute.
Show expected output
Body uses system-ui first and ends with sans-serif; code uses ui-monospace first and ends with monospace.This is a self-check — compare your result with the expected output above.
The .note rule should have a line height of 1.7, but the font shorthand below resets it. Rewrite the rule so the final result is italic, weight 600, size 1.1rem, line-height 1.7 and family Georgia with a serif fallback. You may use the shorthand with the slash syntax or longhand properties.
Press Run to execute.
Show expected output
The note is italic, weight 600, 1.1rem, Georgia with serif fallback and line-height 1.7.This is a self-check — compare your result with the expected output above.
Write a function pickFont(stack, installed) that mimics the browser: given an array stack of font names and an array installed of available fonts, return the first font from stack that is in installed. If none match return the last item of the stack (the generic family).
Press Run to execute.
Show expected output
Arial
sans-serif
InterThis is a self-check — compare your result with the expected output above.
Was this page helpful?