font-family – Choosing the Typeface
font-family sets the typeface. You provide a comma-separated list of font names — the browser uses the first one that is available on the user's device. The last item should always be a generic family (serif, sans-serif, monospace, cursive, fantasy) as a final fallback.
/* Font stack — browser tries each in order */
body {
font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
/* Serif font stack */
.article-body {
font-family: Georgia, 'Times New Roman', Times, serif;
}
/* Monospace for code */
code, pre {
font-family: 'Cascadia Code', 'Fira Code', Consolas, 'Courier New', monospace;
}
/* Multi-word font names must be quoted */
h1 { font-family: 'Open Sans', sans-serif; }
Web-Safe Fonts
Web-safe fonts are installed on virtually every device — you can use them without loading anything:
/* Sans-serif */
font-family: Arial, sans-serif;
font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-family: 'Segoe UI', sans-serif; /* Windows system font */
font-family: -apple-system, sans-serif; /* macOS system font */
/* Serif */
font-family: Georgia, serif;
font-family: 'Times New Roman', Times, serif;
/* Monospace */
font-family: Consolas, 'Courier New', monospace;
font-family: 'Lucida Console', monospace;
/* System font stack (recommended for performance) */
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
Roboto, Oxygen, Ubuntu, sans-serif;
Loading Google Fonts
Google Fonts provides 1,500+ free fonts. Add the <link> in your HTML <head>, then use the font name in CSS:
<head>
<!-- Preconnect for performance -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- The font itself -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
</head>
body { font-family: 'Inter', sans-serif; }
h1, h2 { font-family: 'Playfair Display', serif; }
font-size – Setting Text Size
/* Absolute — px is most predictable */
p { font-size: 16px; }
h1 { font-size: 48px; }
/* Relative to root font size — best for accessibility */
/* (root = <html> font-size, usually 16px) */
p { font-size: 1rem; } /* 16px */
h1 { font-size: 3rem; } /* 48px */
small { font-size: 0.875rem; } /* 14px */
/* Relative to parent font size */
.card p { font-size: 1.1em; } /* 10% bigger than parent */
/* Viewport-relative — scales with screen width */
h1 { font-size: clamp(1.8rem, 5vw, 3.5rem); }
/* clamp(min, preferred, max) — responsive without media queries */
/* Named sizes (less precise, avoid in production) */
font-size: small;
font-size: medium;
font-size: large;
font-size: x-large;
Set font-size: 16px on html (or leave it default), then use rem everywhere else. This respects the user's browser font size preferences (accessibility). Use clamp() for headings to get fluid responsive type without media queries.
font-weight – Bold and Thin
/* Numeric values (100–900, increments of 100) */
font-weight: 100; /* Thin */
font-weight: 300; /* Light */
font-weight: 400; /* Regular (normal) */
font-weight: 500; /* Medium */
font-weight: 600; /* SemiBold */
font-weight: 700; /* Bold */
font-weight: 800; /* ExtraBold */
font-weight: 900; /* Black */
/* Keywords */
font-weight: normal; /* = 400 */
font-weight: bold; /* = 700 */
font-weight: lighter; /* one step lighter than parent */
font-weight: bolder; /* one step bolder than parent */
font-style and font-variant
/* Italic */
em, .italic { font-style: italic; }
cite { font-style: italic; }
/* Remove italic from something that's italic by default */
.not-italic { font-style: normal; }
/* Small caps — uppercase letters displayed at small-cap size */
.byline { font-variant: small-caps; }
/* Numeric formatting */
.price { font-variant-numeric: tabular-nums; } /* fixed-width digits */
line-height – Readability Spacing
line-height controls the vertical space between lines of text. It is one of the most important properties for readability.
/* Unitless number — recommended (multiplies the current font-size) */
p { line-height: 1.6; } /* 1.6 × 16px = 25.6px */
h1 { line-height: 1.2; } /* headings need tighter spacing */
code { line-height: 1.5; }
/* Fixed pixel — not recommended (doesn't scale with font-size) */
p { line-height: 24px; }
/* Em or rem */
p { line-height: 1.6em; }
/* Normal — browser default (~1.2) */
p { line-height: normal; }
/* Rule of thumb for body text */
body { line-height: 1.6; } /* minimum for comfortable reading */
Text Alignment and Spacing
/* Horizontal alignment */
text-align: left; /* default in LTR languages */
text-align: center;
text-align: right;
text-align: justify; /* stretches lines to fill width (use with care) */
text-align: start; /* respects text direction (LTR = left, RTL = right) */
/* Letter spacing */
letter-spacing: 0.05em; /* slight open tracking — good for caps */
letter-spacing: 2px; /* fixed — less flexible */
letter-spacing: normal; /* default */
/* Word spacing */
word-spacing: 4px;
word-spacing: 0.2em;
/* Text indentation */
text-indent: 2rem; /* indent first line, like a book paragraph */
/* Vertical alignment (for inline elements) */
vertical-align: baseline;
vertical-align: middle;
vertical-align: top;
vertical-align: sub; /* subscript */
vertical-align: super; /* superscript */
text-decoration – Underlines, Strikethrough
/* Remove underline from links */
a { text-decoration: none; }
/* Add it back on hover */
a:hover { text-decoration: underline; }
/* Strikethrough */
.sale-price del { text-decoration: line-through; }
/* Overline */
.overlined { text-decoration: overline; }
/* Shorthand: line style color thickness */
a { text-decoration: underline dotted #1572B6 2px; }
/* Underline offset (spacing from baseline) */
a { text-underline-offset: 4px; }
/* Remove underline from subscript/superscript */
sub, sup { text-decoration: none; }
text-transform and White Space
/* Transform case in CSS (without changing HTML) */
.nav-link { text-transform: uppercase; }
.card-title { text-transform: capitalize; } /* Title Case */
.byline { text-transform: lowercase; }
button { text-transform: none; } /* override inherited */
/* White space handling */
.code-snippet { white-space: pre; } /* preserve whitespace and line breaks */
.no-wrap { white-space: nowrap; } /* prevent line breaks */
p { white-space: normal; } /* default — wrap at word boundaries */
/* Overflow for text — truncate long text with ellipsis */
.card-title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; /* shows "..." when truncated */
}
/* Multi-line text clamp (limit to N lines) */
.card-desc {
display: -webkit-box;
-webkit-line-clamp: 3; /* show max 3 lines */
-webkit-box-orient: vertical;
overflow: hidden;
}
The font Shorthand
Combine multiple font properties in one declaration:
/* font: style variant weight size/line-height family */
h1 { font: 700 2.5rem/1.2 'Playfair Display', serif; }
p { font: normal 400 1rem/1.6 'Inter', sans-serif; }
/* font: size family — minimum valid shorthand */
small { font: 0.875rem sans-serif; }
Fonts: Fallback Stacks, Web Fonts, and Unitless line-height
You can't guarantee a user has your font, so font-family takes a stack — the browser uses the first available and falls back down the list, ending in a generic family.
body {
font-family: "Inter", "Helvetica Neue", Arial, sans-serif;
/* custom preferred common ALWAYS end generic */
line-height: 1.5; /* unitless — scales with each element's font-size */
}
Loading a custom font
@font-face {
font-family: "Inter";
src: url("inter.woff2") format("woff2");
font-display: swap; /* show fallback text immediately, swap when loaded */
}
font-display: swap matters: without it, the browser may hide text for up to 3 seconds waiting for the font ("flash of invisible text"). swap shows a fallback right away, then swaps — better perceived speed and a Core Web Vitals win.
Unitless line-height: use 1.5, not 150% or 24px. A unitless value is a multiplier each element computes from its own font size, so nested elements with different sizes all get proportional spacing. A fixed px line-height breaks on larger text.
🏋️ Practical Exercise
- Change
font-familywith a fallback stack. - Set
font-sizeandfont-weight. - Adjust
line-heightandletter-spacing. - Align text with
text-align. - Add
text-decorationandtext-transform.
🔥 Challenge Exercise
Style an article’s typography: a readable body font with a fallback stack, a larger bold heading, a comfortable line-height (~1.6), and left-aligned body text. Import a Google Font. Explain why a font fallback stack matters and what a unitless line-height does.
📋 Summary
- font-family — provide a stack of fonts + generic fallback. Load custom fonts via Google Fonts or
@font-face. - font-size — use
remfor accessibility.clamp()for fluid headings. - font-weight — 100–900 numeric or
bold/normalkeywords. - line-height — unitless number (1.5–1.7 for body text, 1.1–1.3 for headings).
- text-align — left, center, right, justify.
- letter-spacing — use
emunits; positive value opens tracking (good for caps). - text-decoration — control underlines, strikethrough, color, and offset.
- text-transform — uppercase, capitalize, lowercase without touching HTML.
- text-overflow: ellipsis — truncate overflowing text with "…"
Interview Questions
- How do you specify a font with fallbacks?
- What is the difference between numeric and keyword
font-weightvalues? - Why use a unitless
line-height? - How do you load a custom or Google Font?
- What does
text-transformdo?
Related Topics
FAQ
The standard is 16px (1rem) for desktop body text — this is the browser default and is well-researched for readability. On mobile, 15–16px is ideal. Anything below 14px is problematic for readability and accessibility. For long-form articles, 17–18px can actually improve reading comfort on large screens. Never go below 14px for body text.
For body text: 1.5–1.7 (unitless). For headings: 1.1–1.3. For compact UI labels: 1.2–1.4. The unitless form is preferred because it scales proportionally when the font-size changes. The W3C accessibility guidelines recommend a line-height of at least 1.5 for body text.
For performance: system fonts are faster — no extra network request. The system font stack (-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif) looks native and loads instantly. For design: Google Fonts give you better aesthetic control and brand consistency. If you use Google Fonts, always add display=swap to the URL and <link rel="preconnect"> tags to minimize load impact.
Use @font-face to load a font file you host yourself:
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2'),
url('/fonts/myfont.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap; /* show fallback while loading */
}
body { font-family: 'MyFont', sans-serif; }
Always provide woff2 (best compression, all modern browsers) and woff as fallback.

