Understanding Font Weights: 100 to 900 Explained
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://fontfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://fontfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://fontfyi.com/entity//)
Use the native HTML custom element.
Understanding Font Weights: 100 to 900 Explained
Font weight is one of the most expressive typographic tools available in CSS. The spectrum from 100 (ultra-thin) to 900 (ultra-black) creates a visual hierarchy that guides the eye, communicates importance, and establishes brand character.
Yet font weights are widely misunderstood. Developers frequently set font-weight: bold without knowing what weight value that resolves to, load weights that don't actually exist in a given font, or unknowingly rely on the browser's weight synthesis, which produces noticeably inferior results.
This guide covers the full weight system: what the values mean, how named keywords map, how variable fonts change the game, what happens when a weight is missing, and how to load multiple weights efficiently.
The 100-900 Weight Scale
CSS defines font weight on a numeric scale from 1 to 1000, though in practice the values are expressed in multiples of 100 from 100 to 900. These values map to the weight names used in traditional typography and in font file naming conventions.
.weight-100 { font-weight: 100; } /* Thin / Hairline */
.weight-200 { font-weight: 200; } /* Extra Light / Ultra Light */
.weight-300 { font-weight: 300; } /* Light */
.weight-400 { font-weight: 400; } /* Regular / Normal */
.weight-500 { font-weight: 500; } /* Medium */
.weight-600 { font-weight: 600; } /* Semi Bold / Demi Bold */
.weight-700 { font-weight: 700; } /* Bold */
.weight-800 { font-weight: 800; } /* Extra Bold / Ultra Bold */
.weight-900 { font-weight: 900; } /* Black / Heavy */
Each step in the scale is a 100-unit increment. With static fonts, you are limited to these specific values — and only the values for which you have loaded a font file. With variable fonts, any numeric value between 1 and 1000 is valid.
Practical Weight Usage in UI Design
Most interfaces use three to four distinct weights:
:root {
--weight-light: 300; /* Decorative, large display text */
--weight-regular: 400; /* Body copy, default */
--weight-medium: 500; /* UI labels, slightly emphasized text */
--weight-semibold: 600; /* Sub-headings, strong emphasis */
--weight-bold: 700; /* Headings, strong CTAs */
}
body { font-weight: var(--weight-regular); }
.label { font-weight: var(--weight-medium); }
h3, h4 { font-weight: var(--weight-semibold); }
h1, h2 { font-weight: var(--weight-bold); }
Using too many weights creates visual noise and increases download size. Loading three or four is usually enough for a complete visual hierarchy.
Named Weights: Thin, Light, Regular, Bold, Black
In addition to numeric values, CSS provides two keyword values: normal and bold.
/* Keyword equivalents */
.normal { font-weight: normal; } /* Equivalent to 400 */
.bold { font-weight: bold; } /* Equivalent to 700 */
The keywords lighter and bolder are relative to the inherited weight and follow a lookup table:
/* bolder and lighter follow this table:
Inherited: 100-300 → bolder = 400
Inherited: 400-500 → bolder = 700
Inherited: 600-900 → bolder = 900
Inherited: 100-500 → lighter = 100
Inherited: 600-700 → lighter = 400
Inherited: 800-900 → lighter = 700
*/
.parent { font-weight: 400; }
.child { font-weight: bolder; } /* Becomes 700 */
.grandchild { font-weight: bolder; } /* Becomes 900 */
Font Family Naming Conventions
Font families use various naming conventions for their weight variants. These don't always map predictably to CSS values. Here is the common mapping:
| File/Style Name | CSS Value |
|---|---|
| Thin, Hairline | 100 |
| Extra Light, Ultra Light | 200 |
| Light | 300 |
| Regular, Roman, Normal, Book | 400 |
| Medium | 500 |
| Semi Bold, Demi Bold | 600 |
| Bold | 700 |
| Extra Bold, Ultra Bold | 800 |
| Black, Heavy, Ultra Black | 900 |
Some families have additional named weights not covered by CSS: "Compressed", "Ultra Compressed", or brand-specific names like "Display". These may map to non-standard numeric weights or to custom variable font axes.
Which Weights Google Fonts Offers
Not all fonts on Google Fonts offer all nine weights. Some highlights:
Inter: 100, 200, 300, 400, 500, 600, 700, 800, 900 (variable font, full range) Roboto: 100, 300, 400, 500, 700, 900 Open Sans: 300, 400, 500, 600, 700, 800 Lato: 100, 300, 400, 700, 900 Montserrat: 100, 200, 300, 400, 500, 600, 700, 800, 900
Always check which weights a font actually offers before designing around a weight. Loading a weight that doesn't exist triggers weight synthesis, which is covered below.
Font Weight in Variable Fonts
Variable fonts fundamentally change how font weight works. Instead of discrete files for specific weights, a single variable font file contains the entire weight spectrum defined by the type designer.
/* Variable font with full weight range */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter-Variable.woff2') format('woff2');
font-weight: 100 900; /* Range — covers any value in between */
font-display: swap;
}
/* Now any numeric weight value is valid */
.hero-thin { font-weight: 100; }
.body-text { font-weight: 400; }
.ui-medium { font-weight: 500; }
.half-step { font-weight: 450; } /* Not possible with static fonts */
.almost-bold { font-weight: 650; } /* Not possible with static fonts */
.heading { font-weight: 700; }
.extra-heavy { font-weight: 850; } /* Not possible with static fonts */
The ability to specify non-multiple-of-100 weight values is one of the most useful capabilities of variable fonts in practice. It enables:
Dark mode weight adjustment: Dark backgrounds make text appear optically heavier. Reducing weight from 400 to 370 on dark backgrounds maintains the same perceived weight:
@media (prefers-color-scheme: dark) {
body { font-weight: 370; } /* Slightly lighter than 400 */
strong { font-weight: 580; } /* Slightly lighter than 600 */
}
Optical weight matching: Large text at the same font-weight value looks heavier than small text. Reducing weight slightly for display sizes matches the visual weight to the designer's intent:
h1 {
font-size: 4rem;
font-weight: 680; /* Feels like 700 but optically correct at large size */
}
h3 {
font-size: 1.5rem;
font-weight: 700; /* Standard bold at normal heading size */
}
Smooth hover animations: Animating weight on hover creates a satisfying interactive effect without layout shift (since variable font weight changes don't change metrics significantly in most cases):
.nav-link {
font-weight: 400;
transition: font-weight 200ms ease;
}
.nav-link:hover {
font-weight: 600;
}
Weight Synthesis: What Happens When a Weight Is Missing
When you request a font-weight that the font family doesn't have a file for, the browser synthesizes it. This is automatic and silent — there's no error.
How Synthesis Works
Bold synthesis: When you request font-weight: 700 but only 400 is loaded, the browser applies an algorithmic darkening/thickening of the 400 strokes. The result is almost always visually inferior to a properly designed bold face — it applies a uniform stroke widening that doesn't account for the optical adjustments a type designer makes when drawing a bold weight.
Thin/light synthesis: When you request font-weight: 300 but only 400 is loaded, the browser applies an algorithmic thinning. The results are similarly imperfect.
/* This triggers synthesis if only the regular (400) weight is loaded */
strong {
font-weight: bold; /* 700 — will be synthesized if 700 isn't loaded */
}
/* To prevent synthesis, load the weight you need */
@font-face {
font-family: 'Open Sans';
src: url('/fonts/OpenSans-Bold.woff2') format('woff2');
font-weight: 700; /* Load the real bold */
font-display: swap;
}
Detecting Synthesis Problems
You can see synthesis in action by comparing text rendered in a synthesized weight versus a proper weight. The most visible difference is usually: - Synthesized bold: uniform stroke widening, sometimes blurry, poor spacing - Real bold: carefully adjusted strokes, maintained spacing, intentional design
Open browser DevTools and look at the "Fonts" section of the Elements panel. Chrome DevTools shows you exactly which font file is being used for each element, and whether synthesis is being applied.
Disabling Synthesis
You can prevent the browser from synthesizing weights using font-synthesis:
/* Disable all synthesis */
body {
font-synthesis: none;
}
/* Disable only weight synthesis (allow style synthesis) */
body {
font-synthesis: style;
}
/* Disable only italic synthesis (allow weight synthesis) */
body {
font-synthesis: weight;
}
Setting font-synthesis: none means that if a requested weight isn't available, the browser renders the nearest available weight instead of synthesizing. This can result in text that's lighter or heavier than intended, but it prevents the quality degradation of synthesis.
The right approach is to load the weights you need rather than rely on synthesis at all.
Best Practices for Loading Multiple Weights
1. Load Only What You Need
Every weight variant is a separate file download (for static fonts) or increases the size of the variable font file. Audit your design and load only the weights you actually use.
/* Audit your design — do you actually need all these? */
@font-face { font-weight: 100; src: url('thin.woff2'); } /* Thin headlines? */
@font-face { font-weight: 200; src: url('el.woff2'); } /* Rarely needed */
@font-face { font-weight: 300; src: url('light.woff2'); } /* Subheadings? */
@font-face { font-weight: 400; src: url('regular.woff2'); } /* Body — YES */
@font-face { font-weight: 500; src: url('medium.woff2'); } /* UI labels? */
@font-face { font-weight: 600; src: url('semibold.woff2'); } /* Strong labels? */
@font-face { font-weight: 700; src: url('bold.woff2'); } /* Headings — YES */
@font-face { font-weight: 800; src: url('extrabold.woff2'); } /* Rarely needed */
@font-face { font-weight: 900; src: url('black.woff2'); } /* Display only */
For most body-copy-focused sites, you need exactly two weights: 400 and 700. For UI-heavy applications, add 500 or 600.
2. Prefer Variable Fonts for Multiple Weights
If you need three or more weights, a variable font is almost always more efficient:
/* Static: 4 files, 4 HTTP requests, ~68 KB total */
@font-face { font-weight: 300; src: url('light.woff2'); }
@font-face { font-weight: 400; src: url('regular.woff2'); }
@font-face { font-weight: 600; src: url('semibold.woff2'); }
@font-face { font-weight: 700; src: url('bold.woff2'); }
/* Variable: 1 file, 1 HTTP request, ~45 KB, full range */
@font-face {
font-weight: 100 900;
src: url('variable.woff2') format('woff2');
}
3. Define Weight Variables Once
:root {
--weight-body: 400;
--weight-ui: 500;
--weight-emphasis: 600;
--weight-heading: 700;
--weight-display: 800;
}
body { font-weight: var(--weight-body); }
.label { font-weight: var(--weight-ui); }
strong, b { font-weight: var(--weight-emphasis); }
h3, h4, h5 { font-weight: var(--weight-heading); }
h1, h2 { font-weight: var(--weight-display); }
This makes weight auditing simple: look at your :root variables to see every weight in use, and ensure each maps to a loaded font face.
4. Preload the Most Critical Weight
For your primary body font, preload the regular (400) weight to eliminate render-blocking:
<!-- Preload the most critical weight — regular body text -->
<link
rel="preload"
href="/fonts/inter-400.woff2"
as="font"
type="font/woff2"
crossorigin
>
Non-critical weights (bold for headings, etc.) can load on demand without preloading.
5. Use font-display: swap
Always include font-display: swap so users see text in the fallback font immediately rather than waiting for the web font:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-400.woff2') format('woff2');
font-weight: 400;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-700.woff2') format('woff2');
font-weight: 700;
font-display: swap;
}
The weight scale is one of the most powerful tools in your typographic toolkit. Used well — with deliberate choices about which weights to load, careful matching of weights to their intended use, and an understanding of how variable fonts expand the possibilities — it creates a clear, legible visual hierarchy with minimal overhead.
타이포그래피 용어
도구 사용해 보기
언급된 폰트
Christian Robertson이 Google의 Material Design 생태계를 위해 설계한 이 네오 그로테스크 산세리프체는 웹과 Android에서 가장 널리 사용되는 서체입니다. 이중적인 설계 방식이 기계적 정밀함과 자연스러운 읽기 리듬을 균형 있게 결합하여, UI 레이블과 장문 텍스트 모두에 잘 어울립니다. 가변 폰트는 너비 및 굵기 축을 지원하며, 키릴 문자, 그리스 문자, 확장 라틴 스크립트를 함께 포함하고 있습니다.
Rasmus Andersson이 수년에 걸쳐 컴퓨터 화면을 위해 정제한 이 네오 그로테스크체는 디지털 디스플레이의 소형 크기에서 높은 가독성을 위해 자간, x-높이, 획 대비를 최적화했습니다. 광학 크기 축(opsz)을 통해 캡션과 헤드라인에 따라 디자인이 자동으로 조정되며, 굵기 축은 얇은 것부터 블랙까지 전체 범위를 커버합니다. 전 세계 대시보드, 문서화 사이트, 개발자 도구의 사실상 표준 선택으로 자리잡았습니다.
부에노스아이레스 몬세라트 지구의 기하학적 간판과 상점가에서 영감을 받아 Julieta Ulanovsky가 20세기 초 도시 레터링의 정신을 담아 만든 서체입니다. 깔끔한 원형 형태와 강렬한 기하학적 비례감은 헤드라인, 브랜딩, 랜딩 페이지에 어울리는 강렬한 존재감을 자아냅니다. 가변 굵기 축이 넓은 범위를 지원하며, 키릴 문자와 베트남어 스크립트가 포함되어 있습니다.