Chapter 6: CSS Typography, Web Safe Fonts & Text Effects
Typography is the foundation of web design and readability. Mastering font families, web safe fallbacks, custom @font-face web fonts, text shadows, line-height geometry, writing modes, and multi-column text layouts allows you to create editorial-grade web experiences.
6.1 Font Family, Font Stacks & Web Safe Fallback Fonts
The font-family property specifies a prioritized list of font family names for an element. Browsers walk down the font stack from left to right, rendering the first font installed on the user's system or loaded via web fonts.
| Category | Standard Web Safe Font Stack | Generic Family | Visual Appearance & Usage |
|---|---|---|---|
| Sans-Serif (Clean) | system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif |
sans-serif |
Modern, clean, highly readable on digital screens and mobile devices. |
| Serif (Editorial) | "Georgia", "Times New Roman", Garamond, serif |
serif |
Classic, formal, traditional print aesthetic for long-form blog posts and journalism. |
| Monospace (Code) | "Fira Code", "Cascadia Code", Consolas, "Courier New", monospace |
monospace |
Fixed-width characters, ideal for code blocks, terminal outputs, and data tables. |
| Cursive / Handwriting | "Brush Script MT", "Comic Sans MS", cursive |
cursive |
Decorative, informal, signature headers and script branding. |
Modern System Font Stack Best Practice
Using system-ui or native system font stacks provides instant page rendering with 0 KB font network download, using the operating system's native UI font (SF Pro on macOS/iOS, Segoe UI on Windows, Roboto on Android):
<!DOCTYPE html>
<html>
<head>
<style>
body { background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
.font-row { display: flex; flex-direction: column; gap: 12px; }
.font-box { background: #1e293b; border-radius: 8px; padding: 14px 18px; }
.font-label { font-size: 11px; color: #64748b; font-family: monospace; margin-bottom: 6px; display: block; }
.sample { font-size: 18px; color: #f8fafc; }
.f-system { font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
.f-serif { font-family: 'Georgia', 'Times New Roman', Garamond, serif; }
.f-mono { font-family: 'Fira Code', Consolas, 'Courier New', monospace; }
.f-cursive { font-family: 'Brush Script MT', cursive; }
</style>
</head>
<body>
<h3 style="color:#818cf8;margin-top:0;">Font Family Stacks — Live Comparison</h3>
<div class="font-row">
<div class="font-box">
<span class="font-label">system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif</span>
<div class="sample f-system">The quick brown fox jumps over the lazy dog. 0123456789</div>
</div>
<div class="font-box">
<span class="font-label">'Georgia', 'Times New Roman', serif</span>
<div class="sample f-serif">The quick brown fox jumps over the lazy dog. 0123456789</div>
</div>
<div class="font-box">
<span class="font-label">'Fira Code', Consolas, 'Courier New', monospace</span>
<div class="sample f-mono">const greeting = "Hello World"; // monospace</div>
</div>
<div class="font-box">
<span class="font-label">'Brush Script MT', cursive</span>
<div class="sample f-cursive">The quick brown fox — cursive handwriting style</div>
</div>
</div>
</body>
</html>
6.2 Custom Fonts (@font-face) & Google Fonts Integration
Web fonts allow web designers to use custom typography hosted on self-managed servers or cloud font CDNs like Google Fonts.
Method 1: Google Fonts CDN Integration
Include the font stylesheet in your HTML <head>, then reference the family name in your CSS stylesheet:
<!DOCTYPE html>
<html>
<head>
<!-- Step 1: Load the Google Font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;700;900&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
<style>
body { background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
.font-demo { background: #1e293b; border-radius: 10px; padding: 20px; margin-bottom: 14px; }
.font-label { font-size: 11px; color: #64748b; font-family: monospace; display: block; margin-bottom: 8px; }
/* Step 2: Reference the family name in CSS */
.outfit-regular { font-family: 'Outfit', sans-serif; font-weight: 400; font-size: 1.2rem; }
.outfit-bold { font-family: 'Outfit', sans-serif; font-weight: 700; font-size: 1.4rem; color: #818cf8; }
.outfit-black { font-family: 'Outfit', sans-serif; font-weight: 900; font-size: 1.8rem; color: #6366f1; letter-spacing: -1px; }
.playfair { font-family: 'Playfair Display', serif; font-weight: 700; font-size: 1.6rem; color: #f59e0b; }
</style>
</head>
<body>
<h3 style="color:#818cf8;margin-top:0;font-family:'Outfit',sans-serif;">Google Fonts — Outfit + Playfair Display</h3>
<div class="font-demo">
<span class="font-label">font-family: 'Outfit'; font-weight: 400</span>
<div class="outfit-regular">Regular weight — comfortable body text reading</div>
</div>
<div class="font-demo">
<span class="font-label">font-family: 'Outfit'; font-weight: 700</span>
<div class="outfit-bold">Bold weight — subheadings and UI labels</div>
</div>
<div class="font-demo">
<span class="font-label">font-family: 'Outfit'; font-weight: 900</span>
<div class="outfit-black">Black weight — hero display headings</div>
</div>
<div class="font-demo">
<span class="font-label">font-family: 'Playfair Display'; font-weight: 700</span>
<div class="playfair">Editorial Serif — Blog & Magazine Headings</div>
</div>
</body>
</html>
Method 2: Custom Self-Hosted @font-face
Self-hosting fonts eliminates third-party tracking, improves privacy compliance (GDPR), and guarantees offline font availability:
/* In your external styles.css file: */
@font-face {
font-family: 'CustomSans';
src: url('/fonts/custom-sans.woff2') format('woff2'),
url('/fonts/custom-sans.woff') format('woff');
font-weight: 400 700; /* Variable font weight range */
font-style: normal;
font-display: swap; /* Prevents FOIT (Flash of Invisible Text) */
}
body {
font-family: 'CustomSans', system-ui, sans-serif;
}
Font Loading Optimization with font-display: swap
Setting font-display: swap instructs the browser to immediately render text using a system fallback font while the web font is downloading, preventing blank invisible text flashes!
6.3 Font Metrics, Line-Height Geometry & Spacing
Fine-tuning text dimensions, line spacing, and character tracking ensures comfortable reading dynamics across device screens.
| Property | Recommended Values | Description & Impact |
|---|---|---|
line-height |
1.5 to 1.7 (unitless ratio) |
Vertical line spacing. Unitless ratios scale proportionally with font size without compounding inheritance bugs! |
letter-spacing |
0.05em, -0.02em, 1px |
Adjusts tracking space between individual characters. Use negative values for large bold display headings. |
word-spacing |
0.2em, 4px |
Adjusts whitespace gaps between full words in a paragraph. |
font-weight |
400 (Normal), 700 (Bold), 900 (Black) |
Specifies stroke weight of text characters. |
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
.metric-box { background: #1e293b; border-radius: 8px; padding: 16px; margin-bottom: 14px; }
.metric-label { font-size: 11px; color: #64748b; font-family: monospace; display: block; margin-bottom: 6px; }
h3 { margin-top: 0; color: #34d399; }
.lh-tight { line-height: 1.1; color: #94a3b8; font-size: 14px; }
.lh-normal { line-height: 1.6; color: #94a3b8; font-size: 14px; }
.lh-loose { line-height: 2.0; color: #94a3b8; font-size: 14px; }
.ls-tight { letter-spacing: -0.05em; font-size: 1.5rem; font-weight: 700; color: #818cf8; }
.ls-normal { letter-spacing: 0; font-size: 1.5rem; font-weight: 700; color: #818cf8; }
.ls-wide { letter-spacing: 0.15em; font-size: 1.5rem; font-weight: 700; color: #818cf8; text-transform: uppercase; }
.fw-light { font-weight: 300; font-size: 1.1rem; }
.fw-normal { font-weight: 400; font-size: 1.1rem; }
.fw-bold { font-weight: 700; font-size: 1.1rem; color: #f59e0b; }
.fw-black { font-weight: 900; font-size: 1.1rem; color: #ef4444; }
</style>
</head>
<body>
<h3>Typography Metrics — Live Comparison</h3>
<div class="metric-box">
<span class="metric-label">line-height comparison (tight → normal → loose)</span>
<div class="lh-tight">line-height: 1.1 — cramped! Hard to read in paragraphs. CSS is the language of the web, it controls typography spacing and visual rhythm.</div>
</div>
<div class="metric-box">
<span class="metric-label">line-height: 1.6 (recommended for body text)</span>
<div class="lh-normal">line-height: 1.6 — comfortable! This is the recommended line-height for body text, giving readers enough breathing room between lines.</div>
</div>
<div class="metric-box">
<span class="metric-label">line-height: 2.0 (loose/airy)</span>
<div class="lh-loose">line-height: 2.0 — airy! Works well for short UI captions or highlighted text, but too spread for long paragraphs.</div>
</div>
<div class="metric-box">
<span class="metric-label">letter-spacing variants</span>
<div class="ls-tight">letter-spacing: -0.05em (tight display)</div>
<div class="ls-normal">letter-spacing: 0 (default)</div>
<div class="ls-wide">letter-spacing: 0.15em (uppercase spread)</div>
</div>
<div class="metric-box">
<span class="metric-label">font-weight: 300 / 400 / 700 / 900</span>
<div class="fw-light">font-weight: 300 — Light</div>
<div class="fw-normal">font-weight: 400 — Normal</div>
<div class="fw-bold">font-weight: 700 — Bold</div>
<div class="fw-black">font-weight: 900 — Black (Heavy)</div>
</div>
</body>
</html>
6.4 Text Shadows, Writing Modes & Text Effects
CSS provides powerful graphic text effects including multi-layered text shadows, vertical text writing modes, and uppercase text transforms.
Text Shadow Syntax Breakdown
text-shadow: offsetX offsetY blurRadius color;
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
.shadow-box { background: #1e293b; border-radius: 8px; padding: 20px; margin-bottom: 14px; text-align: center; }
.shadow-label { font-size: 11px; color: #64748b; font-family: monospace; display: block; margin-bottom: 10px; }
h3 { margin-top: 0; color: #818cf8; }
/* Neon blue glow */
.neon-title {
font-size: 2rem; font-weight: 700; color: #ffffff;
text-shadow: 0 0 10px #3b82f6, 0 0 20px #6366f1, 0 0 30px #818cf8;
}
/* Subtle drop shadow */
.drop-shadow {
font-size: 1.8rem; font-weight: 700; color: #f8fafc;
text-shadow: 2px 3px 6px rgba(0,0,0,0.6);
}
/* 3D Embossed */
.emboss-text {
font-size: 1.8rem; font-weight: 900; color: #94a3b8;
text-shadow: 1px 1px 2px rgba(255,255,255,0.15), -1px -1px 2px rgba(0,0,0,0.8);
}
/* Multi-colour layered */
.rainbow-glow {
font-size: 2rem; font-weight: 800; color: #fff;
text-shadow: -2px 0 #ef4444, 2px 0 #3b82f6, 0 2px 8px #6366f1;
}
</style>
</head>
<body>
<h3>text-shadow Effects Gallery</h3>
<div class="shadow-box">
<span class="shadow-label">text-shadow: 0 0 10px #3b82f6, 0 0 20px #6366f1, 0 0 30px #818cf8</span>
<div class="neon-title">Neon Glow Effect</div>
</div>
<div class="shadow-box">
<span class="shadow-label">text-shadow: 2px 3px 6px rgba(0,0,0,0.6)</span>
<div class="drop-shadow">Subtle Drop Shadow</div>
</div>
<div class="shadow-box">
<span class="shadow-label">text-shadow: 1px 1px 2px light, -1px -1px 2px dark (3D emboss)</span>
<div class="emboss-text">3D Embossed Text</div>
</div>
<div class="shadow-box">
<span class="shadow-label">text-shadow: -2px 0 red, 2px 0 blue, 0 2px indigo (layered)</span>
<div class="rainbow-glow">Multi-Layer Shadow</div>
</div>
</body>
</html>
Vertical Layouts with writing-mode
The writing-mode property defines whether lines of text are laid out horizontally or vertically, essential for East Asian vertical scripts or decorative sidebar titles:
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; display: flex; gap: 24px; align-items: flex-start; }
h3 { margin-top: 0; color: #fbbf24; }
.panel { background: #1e293b; border-radius: 10px; padding: 20px; }
/* Horizontal (default) */
.horizontal-text { font-size: 1rem; color: #94a3b8; }
/* Vertical right-to-left */
.vertical-badge {
writing-mode: vertical-rl;
text-transform: uppercase;
letter-spacing: 4px;
font-weight: 700;
font-size: 0.8rem;
color: #818cf8;
background: rgba(99,102,241,0.15);
padding: 12px 8px;
border-radius: 6px;
border: 1px solid #6366f1;
}
/* Vertical left-to-right */
.vertical-lr {
writing-mode: vertical-lr;
text-transform: uppercase;
letter-spacing: 3px;
font-weight: 700;
font-size: 0.8rem;
color: #34d399;
background: rgba(16,185,129,0.15);
padding: 12px 8px;
border-radius: 6px;
border: 1px solid #10b981;
}
</style>
</head>
<body>
<div class="panel">
<h3>writing-mode Demo</h3>
<p class="horizontal-text">Normal horizontal text (writing-mode: horizontal-tb — default)</p>
</div>
<div class="vertical-badge">vertical-rl</div>
<div class="vertical-lr">vertical-lr</div>
</body>
</html>
6.5 CSS Multi-Column Layouts (column-count & column-gap)
The CSS Multi-column Layout module allows content to flow across multiple columns like a traditional newspaper or magazine layout.
| Multi-Column Property | Syntax Example | Description |
|---|---|---|
column-count |
column-count: 3; |
Divides element content into the specified number of parallel vertical columns. |
column-gap |
column-gap: 2rem; |
Sets the horizontal whitespace gutter between adjacent columns. |
column-rule |
column-rule: 2px solid #3b82f6; |
Draws a vertical divider rule between columns (width, style, color). |
break-inside |
break-inside: avoid; |
Prevents elements (like images or cards) from breaking awkwardly across columns. |
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { margin-top: 0; color: #60a5fa; }
.newspaper-article {
column-count: 3;
column-gap: 24px;
column-rule: 1px solid #334155;
line-height: 1.7;
font-size: 14px;
color: #cbd5e1;
}
.newspaper-article p { margin-top: 0; }
.newspaper-article blockquote {
break-inside: avoid; /* Keeps blockquote intact in one column */
background: rgba(99,102,241,0.15);
border-left: 3px solid #6366f1;
padding: 10px 14px;
margin: 12px 0;
border-radius: 0 6px 6px 0;
font-style: italic;
color: #a5b4fc;
}
.col-headline {
column-span: all; /* Headline spans all columns */
text-align: center;
font-size: 1.4rem;
font-weight: 700;
color: #f8fafc;
border-bottom: 1px solid #334155;
padding-bottom: 12px;
margin-bottom: 16px;
}
</style>
</head>
<body>
<h3>Multi-Column Newspaper Layout</h3>
<div class="newspaper-article">
<div class="col-headline">CSS Typography — The Designer's Guide</div>
<p>Typography is the art and technique of arranging type to make written language legible, readable, and appealing when displayed. CSS provides fine-grained control over every aspect.</p>
<blockquote>"Good typography is invisible. Bad typography is everywhere." — Robert Bringhurst</blockquote>
<p>The column-count property divides content into parallel vertical columns. Combined with column-gap and column-rule, it produces editorial-grade newspaper and magazine layouts entirely in CSS.</p>
<p>The break-inside: avoid rule prevents blockquotes and pull-quote boxes from being split awkwardly across two column boundaries — a crucial detail for professional multi-column layouts.</p>
<p>Font metrics including line-height, letter-spacing and word-spacing all play critical roles in the overall readability and typographic rhythm of your content.</p>
</div>
</body>
</html>
6.6 Interactive Sandbox — Typography & Multi-Columns
Experiment live with Google Fonts, text shadows, line-height, letter-spacing, and multi-column article layouts in the playground below: