CSS Typography
Control fonts, sizes, weights, spacing, and text styling to create readable, professional designs.
1. Introduction
Typography is the art of arranging type — the fonts, sizes, weights, spacing, and alignment of text. It accounts for about 95% of web design since most web content is text. Poor typography makes a page look unprofessional and hard to read. Good typography makes content easy to scan and a pleasure to read.
In this lesson you will learn all the CSS properties that control how text looks:
- Font properties: family, size, weight, style, variant
- Text properties: alignment, decoration, transform, spacing
- Line and word spacing
- Web fonts: loading custom fonts with Google Fonts
- Text overflow: truncation and ellipsis
2. Theory
Font Family
Sets the typeface (font). Always provide a font stack — a list of fallback fonts in case the first one is not available.
/* Sans-serif (no little feet) — clean, modern */
font-family: 'Inter', Arial, sans-serif;
/* Serif (has little feet) — traditional, editorial */
font-family: Georgia, 'Times New Roman', serif;
/* Monospace (equal character width) — code */
font-family: 'Fira Code', 'Courier New', monospace;
The last value (sans-serif, serif, monospace) is a generic family — a guaranteed fallback built into every browser.
Font Size
font-size: 1rem; /* preferred for body text */
font-size: 18px; /* also common */
font-size: 1.125rem; /* = 18px */
Font Weight
Controls how thick/bold the font strokes are.
font-weight: 400; /* normal/regular */
font-weight: 500; /* medium */
font-weight: 600; /* semibold */
font-weight: 700; /* bold */
font-weight: 800; /* extrabold */
font-weight: 300; /* light */
/* Keywords */
font-weight: normal; /* = 400 */
font-weight: bold; /* = 700 */
Font Style
font-style: normal; /* default */
font-style: italic; /* slanted */
font-style: oblique; /* artificially slanted (fallback for italic) */
Text Alignment
text-align: left; /* default for LTR languages */
text-align: center;
text-align: right;
text-align: justify; /* stretches text to fill the line (avoid for web) */
Text Decoration
text-decoration: none; /* removes underline from links */
text-decoration: underline;
text-decoration: line-through; /* strikethrough */
text-decoration: overline;
/* With colour and style */
text-decoration: underline dotted #2563eb;
Text Transform
text-transform: uppercase; /* ALL CAPS */
text-transform: lowercase; /* all lowercase */
text-transform: capitalize; /* First Letter Of Each Word */
text-transform: none; /* default */
Line Height
Controls the vertical spacing between lines of text. Unitless values are recommended — they are relative to the element's own font size.
line-height: 1; /* tight (line = font size) */
line-height: 1.5; /* comfortable for body text */
line-height: 1.7; /* generous — good for long articles */
line-height: 2; /* loose/relaxed */
Letter Spacing
Controls the space between individual characters.
letter-spacing: 0; /* default */
letter-spacing: 0.05em; /* slightly expanded — good for headings */
letter-spacing: 0.1em; /* more open — good for uppercase labels */
letter-spacing: -0.02em; /* slightly tightened — large display text */
Word Spacing
word-spacing: 0; /* default */
word-spacing: 0.1em; /* increased spacing between words */
Text Overflow
Control what happens when text is too long to fit.
/* Show ellipsis (...) on overflow */
.card-title {
white-space: nowrap; /* prevent text wrapping */
overflow: hidden; /* hide overflow */
text-overflow: ellipsis; /* show ... */
}
/* Clamp to N lines */
.card-excerpt {
display: -webkit-box;
-webkit-line-clamp: 3; /* show max 3 lines */
-webkit-box-orient: vertical;
overflow: hidden;
}
Google Fonts — Loading Custom Fonts
Google Fonts provides hundreds of free web fonts. Add a <link> in the HTML <head>:
<!-- In your HTML head -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Then in CSS -->
body { font-family: 'Inter', sans-serif; }
The font Shorthand
/* font: style weight size/line-height family */
font: italic 700 1.5rem/1.6 'Georgia', serif;
3. Real World Example
Most professional websites use a type scale — a set of consistent font sizes for different content levels:
- Display/Hero heading: 3–4rem, weight 700–800
- Page heading (h1): 2–2.5rem, weight 700
- Section heading (h2): 1.5–2rem, weight 600–700
- Card heading (h3): 1.25rem, weight 600
- Body text: 1rem, weight 400, line-height 1.6
- Small/caption: 0.875rem, weight 400–500
- Label/tag: 0.75rem, weight 600, letter-spacing 0.05em, uppercase
4. Code Example
/* ===== TYPOGRAPHY SYSTEM ===== */
/* Import Google Font */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
/* Base typography */
html {
font-size: 16px;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 1rem;
font-weight: 400;
line-height: 1.6;
color: #1e293b;
}
/* Heading scale */
h1, h2, h3, h4, h5, h6 {
font-weight: 700;
line-height: 1.2;
color: #0f172a;
margin-top: 0;
}
h1 { font-size: 2.5rem; letter-spacing: -0.02em; }
h2 { font-size: 2rem; letter-spacing: -0.01em; }
h3 { font-size: 1.5rem; }
h4 { font-size: 1.25rem; }
h5 { font-size: 1.125rem; }
h6 { font-size: 1rem; }
/* Paragraph */
p {
margin-bottom: 1rem;
max-width: 65ch; /* optimal reading line length */
}
/* Links */
a {
color: #2563eb;
text-decoration: underline;
text-decoration-color: transparent;
transition: text-decoration-color 0.2s;
}
a:hover {
text-decoration-color: currentColor;
}
/* Code */
code {
font-family: 'Fira Code', 'Cascadia Code', monospace;
font-size: 0.875em;
background: #f1f5f9;
padding: 2px 6px;
border-radius: 4px;
}
/* Labels and tags */
.label {
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #64748b;
}
/* Card title with truncation */
.card-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1.25rem;
font-weight: 600;
}
/* Multi-line clamp */
.card-body {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
color: #475569;
}
5. Code Breakdown
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;- A professional font stack. 'Inter' is the custom font.
-apple-systemandBlinkMacSystemFontare system fonts on Mac/iOS that look great.sans-serifis the ultimate fallback. letter-spacing: -0.02emon h1- Large headings look better with slightly tighter letter spacing — the spacing that works for body text feels too loose at large sizes. This is a subtle but professional detail.
text-decoration-color: transparentthencurrentColoron hover- A modern technique: the underline exists but is invisible until hover, where it fades in via transition. This is smoother than adding/removing underline.
font-size: 0.875emon code- Using
emhere (notrem) means code text will be 87.5% the size of its surrounding text — it scales with the parent context, which is correct behaviour. -webkit-line-clamp: 3- Limits the text to 3 lines and shows an ellipsis. This needs the three-property combination to work:
display: -webkit-box,-webkit-box-orient: vertical, andoverflow: hidden.
6. Common Mistakes
-
Using
justifytext alignment. Justified text creates uneven word spacing and "rivers" of white space. Left-aligned text is more readable for web. -
Setting
line-heightwith units. Use unitless values like1.6not1.6em. A unitless value scales correctly when font-size changes; a unit-based value can cause issues in inheritance. - Using too many fonts. Each Google Fonts family is an additional HTTP request. Using 3+ font families slows the page down and looks inconsistent. Stick to 1–2 fonts.
-
Forgetting
text-decoration: noneon links in navbars. Browser default adds underlines to all<a>elements — navigation links should not have underlines. -
Setting line-height too tight.
line-height: 1makes text almost unreadable for paragraphs. Use at least1.5for body text. -
Not loading enough font weights. Loading 'Inter' without specifying weights means you only get one weight. Add
wght@400;600;700in the Google Fonts URL.
7. Best Practices
- Use a consistent type scale — define all heading sizes upfront and stick to them throughout the page.
- Set base typography on
body— font-family, font-size, line-height, color. Elements inherit from body, reducing repetition. - Unitless line-height —
line-height: 1.6notline-height: 1.6em. - Load only needed font weights — fewer weights = faster page load.
- Add
font-display: swapin custom@font-facedeclarations to prevent invisible text during font loading. - Use
max-width: 65chon paragraphs/articles for optimal reading line length. - Remove underlines from navigation links — add them back (or use another indicator) for inline text links.
8. Practice Exercise
Create typography.html and typography.css:
- Import a Google Font (try "Inter" or "Roboto")
- Set a type scale: define sizes for h1 through h4 and body text using
rem - Create a blog article layout:
- Article title (h1) with tight letter-spacing
- Byline label in uppercase small text
- Body paragraphs with line-height 1.7 and max-width 65ch
- A pull-quote in italic, larger text, and a left border
- Create a card with a title that truncates with ellipsis and a body clamped to 3 lines
9. Assignment
Build a complete typographic design system for a fictional company. Requirements:
- Choose and import 2 Google Fonts: one for headings (try 'Playfair Display' or 'Merriweather'), one for body text (try 'Inter' or 'Source Sans 3')
- Define a full heading scale (h1–h6) with appropriate sizes, weights, and letter-spacing
- Style paragraphs, lists, blockquotes, and code elements
- Create a "Type Specimen" page that shows all these styles in a demo layout
- Make all links styled with a custom hover effect using transitions
- Add a section showing all font weights available for your chosen font
10. Interview Questions
Q1: What is a font stack and why do we use one?
Answer: A font stack is a comma-separated list of font families in CSS, e.g. 'Inter', Arial, sans-serif. We use it because the browser tries each font in order — if 'Inter' is not available, it falls back to Arial, then to any system sans-serif. This ensures text always displays in a suitable font.
Q2: What is the recommended line-height for body text?
Answer: Between 1.5 and 1.7 for body text. Unitless values are recommended (e.g. line-height: 1.6) because they scale correctly when font-size changes — unitless means "multiply by the element's font-size".
Q3: How do you load a custom font in CSS?
Answer: You can use a service like Google Fonts by adding a <link> element in the HTML head that imports the font CSS. Or use @font-face in your CSS to load font files directly. After linking, reference the font name in font-family.
Q4: How do you truncate text with an ellipsis in CSS?
Answer: You need three properties together: white-space: nowrap (prevents line wrapping), overflow: hidden (hides the overflow), and text-overflow: ellipsis (shows "..." at the cutoff point). For multi-line truncation, use -webkit-line-clamp.
Q5: What is text-transform and when would you use it?
Answer: text-transform changes the capitalisation of text using CSS. uppercase is commonly used for labels, navigation items, and section tags. capitalize is used for titles. The advantage of using CSS over writing uppercase in HTML is that the actual content remains mixed case in the source for screen readers and search engines.
11. Additional Resources
- Google Fonts — fonts.google.com
- MDN Web Docs — CSS Font properties (search "MDN CSS font")
- Type Scale — typescale.com (visual type scale generator)
- Fontpair — fontpair.co (Google Fonts pairing suggestions)
- The Elements of Typographic Style Applied to the Web — webtypography.net