
How many fonts should you use on one website?
- Sajjad
- Typography
- 11 Oct, 2026
Most websites should use one or two typefaces, and rarely more than three. A single well-chosen family can handle body text, headings and interface elements on its own, while a second family adds contrast, typically for headings or for code. A third is only worth adding when it has a specific job, such as a monospace for technical content. Just as important as the number of typefaces is the number of font files: two families in four weights each is eight downloads, so aim for roughly two to six font files in total. Fewer fonts means faster pages, a more consistent look and fewer decisions every time you design a new component.
Adding fonts feels like adding personality, but past a certain point it adds noise instead. Every extra family makes the page heavier, increases the chance of layout shift as fonts load, and makes the design harder to keep consistent across a growing site. In this article you'll learn why one or two typefaces is the usual answer, how to tell typefaces from fonts from files, when a third family is justified, how to audit what a page actually loads, and how to set up a small type system in CSS that stays lean.
Typefaces, Fonts and Files
The question "how many fonts?" is ambiguous, so it helps to separate three things:
- Typeface or family: The design, such as Inter or Merriweather. This is usually what people mean by "a font".
- Style: One weight and posture of that family, such as Inter SemiBold or Merriweather Italic.
- File: What the browser downloads. With static fonts, each style is one file. With a variable font, one file can contain a whole range of weights.
Limiting typefaces protects visual consistency. Limiting styles and files protects performance. You need to think about both.
| Setup | Typefaces | Styles | Typical files |
|---|---|---|---|
| One sans, static | 1 | Regular, Italic, SemiBold, Bold | 4 |
| One sans, variable | 1 | Any weight, upright and italic | 2 |
| Serif body, sans headings | 2 | Serif Regular, Italic, Bold; Sans SemiBold | 4 |
| Sans plus mono for docs | 2 | Sans Regular, Bold; Mono Regular | 3 |
Why One or Two Is Usually Enough
One Family Can Do a Lot
A good text family with a range of weights already gives you plenty of hierarchy. Size, weight, colour, letter case and spacing can separate a page title from a section heading from a caption without switching typeface. Many product interfaces and documentation sites use a single sans family throughout, sometimes with a mono for code.
Two Families Give Contrast With Control
A second family is useful when you want headings to feel distinctly different from body text, for example a serif for long-form articles paired with a sans for navigation and headings, or the reverse. Two families still feel like a deliberate pairing. Beyond that, readers start to sense that the page lacks a system, even if they can't say why.
Each Addition Has a Cost
- Performance: More files means more bytes and more requests competing with images and scripts.
- Layout stability: Every web font that swaps in after the fallback can shift text. More families means more opportunities for shift.
- Consistency: With three or four families, designers and developers need rules for which one goes where. Without them, new pages drift.
- Maintenance: Each family needs fallback stacks, licences checked and updates tracked.
When a Third Family Is Justified
A third typeface should have a role that neither of the others can fill. Common legitimate reasons:
- Code and data: Technical sites need a monospace for code blocks, terminal output and IDs. A system monospace stack often works, which costs nothing to download.
- A logo or display face: A brand display font used only in the hero or for very large headlines. Even then, consider whether the logo should simply be an SVG.
- Script coverage: A multilingual site may need a separate family for Arabic, Devanagari or CJK text if the main family doesn't cover it. That is the same role in a different script, not a new voice.
If you can't state the job in one sentence, you probably don't need the font. If you want related styles that are guaranteed to work together, a superfamily is a good option; see what superfamilies are and why they help with pairing.
How Many Weights and Styles?
Weights multiply quickly, so budget them like typefaces.
- Body family: Regular, Italic and Bold cover nearly all running text. Add Bold Italic only if your content actually uses it.
- Heading family: One or two weights, such as SemiBold for headings and Regular for subtitles.
- Monospace: Regular is often enough. Bold is useful for syntax highlighting themes that rely on weight.
If you leave out a style that your CSS asks for, browsers may synthesise it by slanting or smearing the regular font, which looks noticeably worse than the real thing. You can prevent this so a missing style is obvious during development:
html {
font-synthesis: none;
}
With this set, a font-weight: 700 on a family that only has 400 loaded will render at 400, so you'll spot the missing file rather than shipping a fake bold. You can be more targeted with font-synthesis-weight: none or font-synthesis-style: none if you only want to block one kind of synthesis.
Variable Fonts Change the Maths
A variable font packs a continuous range of weights, and sometimes widths, into one file. One upright file plus one italic file can replace six or more static files. The file is larger than any single static style, but usually smaller than the combined set once you use more than two or three weights. If you need many weights, variable is usually the leaner option.
Audit What a Page Actually Loads
Before deciding to cut fonts, measure. Open the browser's developer tools, go to the Network panel, filter by Font and reload. Or run this in the console after the page has loaded:
const fontFiles = performance
.getEntriesByType("resource")
.filter((r) => /\.(woff2?|ttf|otf)(\?|$)/.test(r.name));
const totalKb = fontFiles.reduce((sum, r) => sum + r.transferSize, 0) / 1024;
console.log(`${fontFiles.length} font files, ${totalKb.toFixed(1)} KB transferred`);
7 font files, 214.6 KB transferred
A transferSize of 0 means the file came from cache or the server didn't send timing headers for a cross-origin request, so test in a fresh private window for accurate numbers.
You can also see which families the page is actually rendering:
await document.fonts.ready;
const loaded = [...document.fonts]
.filter((face) => face.status === "loaded")
.map((face) => `${face.family} ${face.weight} ${face.style}`);
console.log(loaded);
["Inter 400 normal", "Inter 600 normal", "Inter 400 italic", "Lora 700 normal"]
Compare this list with your design. Styles that appear in the network panel but are rarely used on the page are candidates for removal.
Set Up a Small Type System in CSS
The easiest way to keep the count low is to make font choices in one place and refer to them by role everywhere else.
:root {
/* Two families, with fallbacks */
--font-text: "Source Serif 4", Georgia, "Times New Roman", serif;
--font-ui: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
/* A free monospace from the system, no download */
--font-code: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
/* Only the weights you load */
--weight-regular: 400;
--weight-strong: 700;
--weight-heading: 600;
}
body {
font-family: var(--font-text);
font-weight: var(--weight-regular);
}
strong,
b {
font-weight: var(--weight-strong);
}
h1,
h2,
h3,
h4,
.button,
.nav,
.label {
font-family: var(--font-ui);
font-weight: var(--weight-heading);
}
code,
pre,
kbd {
font-family: var(--font-code);
}
Then make it hard to break. If you use Stylelint, you can block hard-coded font-family values outside the root variables:
{
"rules": {
"declaration-property-value-allowed-list": {
"font-family": ["/^var\\(--font-/", "inherit"]
}
}
}
Now any component that tries to introduce a new font fails the lint step, and the conversation about whether that font is needed happens before it ships.
Load Only What the System Declares
Match your @font-face rules to the variables. With the setup above you self-host four files:
@font-face {
font-family: "Source Serif 4";
src: url("/fonts/source-serif-4-regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Source Serif 4";
src: url("/fonts/source-serif-4-italic.woff2") format("woff2");
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Source Serif 4";
src: url("/fonts/source-serif-4-bold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter";
src: url("/fonts/inter-variable.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
The browser only downloads a face when text on the page actually uses it, so a declared but unused style costs very little. The real savings come from not using extra styles in the first place.
Signs You Have Too Many Fonts
Watch for these symptoms in an existing site:
- Every section looks different: Landing pages, blog posts and the app feel like separate products.
- Near-duplicate families: Two similar sans-serifs, such as one for headings and one for body, that readers can't tell apart. That is cost without contrast.
- Fonts used once: A family that appears only in the footer or a single banner.
- Long font lists in CSS: Many
@font-facerules or a Google Fonts URL with half a dozen families. - Noticeable reflow: Text jumps more than once as different fonts arrive.
Fixing it usually means picking the strongest body family, choosing at most one partner, and mapping every old usage onto one of those two roles.
A Quick Decision Guide
- Start with one family for everything and see if size and weight give you enough hierarchy.
- Add a second family only if headings or the brand need a distinctly different voice.
- Use the system monospace for code unless code is central to the site.
- Cap styles at around six across all families, fewer if you can.
- Prefer variable fonts when you need more than three weights of one family.
- Review periodically with a network audit, because fonts creep in over time.
FAQ: How Many Fonts to Use
No. One well-designed family with a few weights is often the cleanest option. Size, weight, colour and spacing provide plenty of hierarchy, and you load fewer files.
For design consistency, no, because it is part of the same family. For performance, yes, because each static weight is usually a separate file the browser has to download.
For visual consistency, yes, because they still add another voice to the page. For performance they cost nothing, since they're already installed, which makes a system monospace a good choice for code.
Ideally none. Export the logo as SVG so its lettering doesn't depend on loading a font, and keep the brand typeface for headings only if it is genuinely needed elsewhere.
Not always. A single variable file is larger than a single static weight. It wins when you would otherwise load several weights of the same family.
Icon fonts add another font file and have accessibility drawbacks. Most sites are better off with inline SVG icons, which don't count against your font budget at all.
Conclusion
For most websites the right number of typefaces is one or two, with a third only when it does a job the others can't, such as monospace for code or coverage for another script. Think in files as well as families: a small set of weights, ideally from variable fonts where you need many, keeps pages fast and stable.
Define your families and weights once as variables, map every element to a role, and audit what the browser actually downloads from time to time. A restrained type system is easier to build with, faster to load and more consistent for readers, which is exactly what good typography should be.


