
How to use font weight to create hierarchy?
- Sajjad
- Typography
- 11 Oct, 2026
You use font weight to create hierarchy by making the most important text heavier and the least important text lighter, so readers can tell what matters at a glance without relying on size alone. In practice that means choosing a small set of weights, often regular (400) for body text, a semibold or bold (600 or 700) for headings and key labels, and perhaps a medium (500) for interface elements. The difference between levels needs to be clear enough to notice, which usually means skipping at least one step on the 100 to 900 scale. Weight works best alongside size, colour and spacing rather than on its own. Used with restraint, it lets you build hierarchy even in compact layouts where you can't make text much bigger.
Hierarchy is what lets people scan a page, find the section they want and understand how pieces of information relate. Weight is one of the cheapest and most flexible tools for that, but it's also easy to overuse until everything shouts. In this article you'll learn how the CSS weight scale works, how much contrast between weights you need, how to combine weight with other signals, how to set it up in CSS and with variable fonts, and the mistakes that flatten a hierarchy.
How the Font Weight Scale Works
CSS describes weight on a numeric scale from 1 to 1000, but most fonts are designed around the traditional steps of 100 to 900. The common names map roughly like this:
| Value | Common name |
|---|---|
| 100 | Thin (Hairline) |
| 200 | Extra Light |
| 300 | Light |
| 400 | Regular (Normal) |
| 500 | Medium |
| 600 | Semibold |
| 700 | Bold |
| 800 | Extra Bold |
| 900 | Black (Heavy) |
The keywords normal and bold equal 400 and 700. The keywords bolder and lighter are relative to the parent's weight, not to the available font files, which can produce surprising results, so it's usually clearer to set numbers explicitly.
What Happens When a Weight Is Missing
If you ask for a weight that isn't loaded, the browser picks the nearest available one using a fallback algorithm. Ask for 600 when only 400 and 700 are loaded and you'll get 700. If you ask for bold and no bold file exists at all, the browser may generate a faux bold by smearing the regular glyphs. Faux bold looks muddy and loses the designer's spacing. You can prevent synthetic bold with:
body {
font-synthesis-weight: none;
}
With synthesis turned off, missing weights fall back to the nearest real weight instead.
How Much Weight Contrast You Need
Readers notice weight differences in relative terms. The jump from 400 to 500 is subtle on screen, especially at small sizes and on low-resolution displays. The jump from 400 to 700 is unmistakable.
- Skip at least one step for distinct levels: 400 and 600, or 400 and 700, read as clearly different. 400 and 500 often look like the same weight to casual readers.
- Use adjacent steps for gentle emphasis: Medium (500) is useful for button labels and navigation, where you want slightly more presence than body text without a full bold.
- Keep the extremes for special cases: Thin and Black weights draw attention fast. They suit large display headings, not interface labels or body text.
- Check the actual font: One family's 600 can be heavier than another family's 700. Judge with your eyes, not just the numbers.
A useful rule of thumb is to have no more than three or four weights in active use on a page. More than that rarely adds clarity and increases the number of font files you need to load.
Combining Weight With Other Signals
Weight is strongest when it works with other cues. The main signals for hierarchy are size, weight, colour, case, spacing and position. You don't need all of them at every level.
Weight and Size
Large text already carries visual weight, so headings don't always need to be heavy. A 40px heading at 600 can feel as strong as a 24px heading at 800. As size increases, you can often reduce weight; as size decreases, weight has to do more of the work.
h1 { font-size: 2.5rem; font-weight: 650; line-height: 1.1; }
h2 { font-size: 1.75rem; font-weight: 650; line-height: 1.2; }
h3 { font-size: 1.25rem; font-weight: 700; line-height: 1.3; }
h4 { font-size: 1rem; font-weight: 700; line-height: 1.4; }
Here the smaller headings get slightly more weight so they stay distinct from bold text in paragraphs. Values like 650 only work with variable fonts; with static fonts, stick to the weights you actually load.
Weight and Colour
Lighter colours reduce the perceived weight of text, and darker colours increase it. That lets you create three or four levels from just two weights:
:root {
--text-strong: #111827;
--text: #1f2937;
--text-muted: #4b5563; /* about 7.5:1 on white */
}
.card-title { font-weight: 600; color: var(--text-strong); }
.card-body { font-weight: 400; color: var(--text); }
.card-meta { font-weight: 400; color: var(--text-muted); font-size: 0.875rem; }
.card-label { font-weight: 600; color: var(--text-muted); font-size: 0.75rem;
text-transform: uppercase; letter-spacing: 0.06em; }
Make sure muted text still meets WCAG contrast: at least 4.5:1 for normal text and 3:1 for large text, where WCAG defines large as at least 18pt, or 14pt when bold (roughly 24px, or about 18.66px bold).
Weight Within Running Text
Inside a paragraph, bold draws the eye to a few key phrases. Use the semantic strong element when the text is genuinely important, and b when you only want visual distinction without implied importance.
<p>
Your backup runs every night at 02:00.
<strong>Restores overwrite existing files</strong>, so download a copy first.
</p>
strong, b {
font-weight: 700;
}
If your body weight is lighter than 400, or your font's bold is very heavy, adjust this so bold text stands out without looking like a black blot.
Building a Weight System in CSS
Treat weights as design tokens, just like colours and spacing. That keeps usage consistent and makes it easy to change later.
:root {
--weight-regular: 400;
--weight-medium: 500;
--weight-semibold: 600;
--weight-bold: 700;
}
body { font-weight: var(--weight-regular); }
h1, h2, h3 { font-weight: var(--weight-semibold); }
button,
.nav-link { font-weight: var(--weight-medium); }
th,
.label { font-weight: var(--weight-semibold); }
strong { font-weight: var(--weight-bold); }
Load only the weights you've defined. With static font files, each weight is a separate file:
@font-face {
font-family: "Source Sans 3";
src: url("/fonts/source-sans-3-400.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Source Sans 3";
src: url("/fonts/source-sans-3-600.woff2") format("woff2");
font-weight: 600;
font-style: normal;
font-display: swap;
}
Using a Variable Font
A variable font with a weight axis stores the whole range in one file. Declare the range in @font-face, then use any value within it:
@font-face {
font-family: "Inter";
src: url("/fonts/InterVariable.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
body { font-family: "Inter", system-ui, sans-serif; font-weight: 400; }
h1 { font-weight: 720; }
.eyebrow { font-weight: 560; }
Variable fonts make fine tuning easy, but the same restraint applies. Having 640 in one place and 660 in another adds nothing a reader will notice. For more on the axes themselves, see what variable fonts are and why you should use them.
Weight in Dark Mode and on Different Screens
Light text on a dark background tends to look heavier than dark text on light, because bright strokes appear to spread slightly. Many designers reduce weight a little in dark themes. With a variable font this is a one-line change:
@media (prefers-color-scheme: dark) {
body { font-weight: 350; }
h1, h2, h3 { font-weight: 600; }
}
Only do this with a variable font or a family that includes those weights, or the browser will round to the nearest available file.
Screen rendering also matters. Thin weights such as 100 to 300 can break up at small sizes on lower-density displays and on Windows, where text rendering differs from macOS. Keep body text at 400 or close to it, and reserve light weights for large text where the strokes still have enough pixels to render cleanly.
Common Mistakes With Font Weight
- Bolding too much: If half the text on a page is bold, nothing stands out. Emphasis is relative.
- Weight steps that are too close: Using 400 for body and 500 for headings at similar sizes looks like a mistake rather than a choice.
- Light body text for elegance: A 300 weight in mid-grey can look refined in a mockup but becomes hard to read on real screens.
- Relying on faux bold: Forgetting to load a bold file gives you synthetic bold, which looks smeared and has poor spacing.
- Using weight as the only signal for links or state: Bold alone isn't enough to show a link, an error or a selected item. Combine it with colour, underline, icons or text.
- Too many weights loaded: Loading eight static weights for a site that uses three adds needless page weight.
A Quick Way to Audit Weight Hierarchy
Squint at your page or blur it slightly. The elements that remain visible should be the ones you want people to notice first. You can simulate this in the browser:
/* Temporary audit style: remove after checking */
html.audit body {
filter: blur(2px) grayscale(1);
}
Toggle it from the console:
document.documentElement.classList.toggle("audit");
With colour removed and detail blurred, weight and size are almost all that remain. If the headings, key figures and primary buttons don't stand out, increase their weight contrast or reduce the weight of competing elements. You can also list every weight in use on a page:
const weights = new Map();
for (const el of document.querySelectorAll("body *")) {
if (!el.textContent.trim()) continue;
const w = getComputedStyle(el).fontWeight;
weights.set(w, (weights.get(w) || 0) + 1);
}
console.table(Object.fromEntries([...weights].sort()));
┌─────────┬────────┐
│ (index) │ Values │
├─────────┼────────┤
│ 400 │ 312 │
│ 600 │ 41 │
│ 700 │ 18 │
└─────────┴────────┘
A short list like this suggests a disciplined system. A long list of slightly different values is a sign of drift.
FAQ: Font Weight and Hierarchy
Three or four is usually enough: regular for body text, a medium for interface elements if needed, and a semibold or bold for headings and emphasis. More weights rarely improve hierarchy and add to page weight with static fonts.
400 is the safe default for most typefaces. Some fonts look slightly light on screen and benefit from 425 to 450 with a variable font. Avoid light weights below 400 for long passages, particularly on dark backgrounds or small sizes.
No. Large headings can work well at semibold or even regular weight because size already creates contrast. Smaller headings usually need more weight to stand apart from body text and bold phrases.
The strong element marks content as important, which assistive technology and search engines can take into account. The b element only draws attention visually without implying importance. Both are usually styled bold.
The browser is probably generating faux bold because the real bold file is not loaded. Add an @font-face rule for the bold weight, or use a variable font, and set font-synthesis-weight to none to stop synthetic bold.
Weight helps, but it should not be the only way you convey meaning or state. Combine it with colour, underlines, icons or text labels, and make sure every weight you use still meets WCAG contrast requirements.
Conclusion
Font weight is one of the most efficient ways to show readers what matters. Choose a small set of weights, make the steps between levels large enough to notice, and let weight work together with size, colour and spacing. Large text can carry a lighter weight, while small headings and labels need more weight to stay distinct.
Set your weights up as tokens, load only the files you use, and turn off synthetic bold so missing files don't degrade quality. Then audit the result by squinting or blurring the page. If the right things still stand out, your weight hierarchy is doing its job.


