Typography Complete
Text comprises approximately 90% of web content, which makes typography one of the most important aspects of web design. Good typography improves readability, establishes hierarchy, and creates visual harmony. This lesson covers everything you need to build professional typographic systems: font selection and loading, modular scales, measure and rhythm, and responsive typography patterns using the custom properties and math functions you have already learned.
Font Selection and Loading
Before you can apply typographic principles, you need to understand how fonts work on the web. Modern CSS provides powerful tools for loading custom fonts and controlling their display behavior.
Understanding @font-face
The @font-face rule makes custom fonts available in your CSS by declaring a font family and pointing to font files. Although services like Google Fonts handle this automatically, understanding @font-face helps you optimize font loading and work with custom or licensed fonts.
@font-face {
font-family: 'Custom Sans';
src: url('/fonts/custom-sans.woff2') format('woff2'),
url('/fonts/custom-sans.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Custom Sans';
src: url('/fonts/custom-sans-bold.woff2') format('woff2'),
url('/fonts/custom-sans-bold.woff') format('woff');
font-weight: 700;
font-style: normal;
font-display: swap;
}
body {
font-family: 'Custom Sans', system-ui, sans-serif;
}
Each @font-face declaration creates a font face with specific weight and style properties. The browser automatically selects the appropriate face when you use font-weight: 700 or similar declarations. The font-display: swap property tells the browser to show fallback text immediately while the custom font loads, preventing invisible text during loading.
Variable Fonts
Variable fonts contain multiple variations within a single file, reducing the number of HTTP requests and giving you fine-grained control over font appearance. Instead of loading separate files for regular, bold, and italic, a variable font provides a range of weights, widths, and styles in one file.
@font-face {
font-family: 'Inter Variable';
src: url('/fonts/inter-variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
/* Use any weight from 100 to 900 */
h1 {
font-family: 'Inter Variable', sans-serif;
font-weight: 650; /* Exact weight, not just 400 or 700 */
}
/* Access custom axes with font-variation-settings */
.heading {
font-family: 'Inter Variable', sans-serif;
font-variation-settings: 'wght' 600, 'slnt' -5;
}
The font-weight range in @font-face tells the browser this font supports weights from 100 to 900. You can then use any value in that range. The font-variation-settings property provides access to custom axes beyond standard weight and style, such as slant, width, or optical size.
Font Loading Strategy
The font-display property controls how browsers handle the period between requesting a font and having it available. Different strategies optimize for different priorities.
@font-face {
font-family: 'Body Font';
src: url('/fonts/body.woff2') format('woff2');
font-display: swap; /* Show fallback immediately, swap when loaded */
}
@font-face {
font-family: 'Heading Font';
src: url('/fonts/heading.woff2') format('woff2');
font-display: optional; /* Use only if cached, otherwise use fallback */
}
Font Display Values: swap shows fallback text immediately and swaps in the custom font when ready (best for body text). optional only uses the custom font if it loads extremely quickly, otherwise sticks with the fallback (good for performance-critical sites). block hides text briefly while loading (avoid this). fallback is a compromise between swap and optional.
Modular Scale and Typographic Harmony
A modular scale creates harmonious relationships between font sizes by using mathematical ratios. Instead of arbitrary sizes, a modular scale generates a predictable, proportional system that creates visual rhythm and hierarchy.
Understanding Modular Scale
A modular scale starts with a base size and multiplies it by a ratio to generate larger and smaller sizes. Common ratios include 1.125 (major second), 1.25 (major third), 1.333 (perfect fourth), 1.5 (perfect fifth), and 1.618 (golden ratio). Each ratio creates a different visual rhythm.
:root {
/* Base size and ratio */
--font-size-base: 1rem;
--scale-ratio: 1.25; /* Major third */
/* Generate scale using calc() */
--font-size-sm: calc(var(--font-size-base) / var(--scale-ratio));
--font-size-md: var(--font-size-base);
--font-size-lg: calc(var(--font-size-base) * var(--scale-ratio));
--font-size-xl: calc(var(--font-size-base) * var(--scale-ratio) * var(--scale-ratio));
--font-size-2xl: calc(var(--font-size-base) * var(--scale-ratio) * var(--scale-ratio) * var(--scale-ratio));
--font-size-3xl: calc(var(--font-size-base) * var(--scale-ratio) * var(--scale-ratio) * var(--scale-ratio) * var(--scale-ratio));
}
/* Apply scale to elements */
p { font-size: var(--font-size-md); }
h4 { font-size: var(--font-size-lg); }
h3 { font-size: var(--font-size-xl); }
h2 { font-size: var(--font-size-2xl); }
h1 { font-size: var(--font-size-3xl); }
By changing only --scale-ratio, you can adjust the entire typographic system. A smaller ratio (like 1.125) creates subtle size differences, while a larger ratio (like 1.618) creates dramatic contrast.
Interactive Modular Scale Demo
Experiment with different ratios to see how they affect typographic hierarchy. Adjust the ratio slider and observe how all heading sizes update proportionally.
Heading 1
Heading 2
Heading 3
Heading 4
Body text
Small textMeasure: Line Length for Readability
Measure refers to the length of a line of text, typically measured in characters. Lines that are too long tire the eyes and make it difficult to find the next line when reading. Lines that are too short create awkward reading rhythm and force the eyes to jump frequently.
The ideal measure is between 45 and 75 characters per line, with 66 characters considered optimal for single-column text. You can control measure using max-width in CSS, typically expressed in ch units where 1ch equals the width of the zero character in the current font.
/* Optimal measure for body text */
p, article {
max-width: 66ch;
}
/* Wider measure for large text */
h1, h2 {
max-width: 45ch;
}
/* Narrower measure for small text */
.small-text {
max-width: 50ch;
}
Using ch units ensures that measure adjusts automatically when font size changes, maintaining readability across different screen sizes and user preferences.
Interactive Measure and Line Height Demo
Experience how measure and line height affect readability. Adjust the controls to see how different combinations impact reading comfort.
Typography is the art and technique of arranging type to make written language legible, readable, and appealing when displayed. The arrangement of type involves selecting typefaces, point sizes, line lengths, line spacing, and letter spacing, and adjusting the space between pairs of letters.
Good typography establishes a strong visual hierarchy, provides a graphic balance to the website, and sets the product's overall tone. Typography should guide and inform your users, optimize readability and accessibility, and ensure an excellent user experience.
The measure (line length) and line height work together to create comfortable reading experiences. Lines that are too long tire the eyes, while lines that are too short create awkward rhythm. Similarly, line height that is too tight makes text feel cramped, while excessive line height disconnects lines from each other.
Whitespace and Vertical Rhythm
Whitespace creates breathing room and guides the eye through content. Proper whitespace management involves line height, spacing between paragraphs, and maintaining consistent vertical rhythm throughout your design.
Line Height (Leading)
Line height controls the vertical space between lines of text. Body text typically needs more line height than headings because longer lines benefit from extra vertical space that helps readers find the next line.
:root {
--line-height-tight: 1.2;
--line-height-normal: 1.5;
--line-height-relaxed: 1.75;
}
/* Headings use tighter line height */
h1, h2, h3, h4 {
line-height: var(--line-height-tight);
}
/* Body text uses comfortable spacing */
p, li {
line-height: var(--line-height-normal);
}
/* Long-form content benefits from extra space */
article p {
line-height: var(--line-height-relaxed);
}
Vertical Rhythm
Vertical rhythm maintains consistent spacing relationships between elements, creating visual harmony. A common approach uses a baseline grid where all vertical spacing is a multiple of a base unit.
:root {
/* Base rhythm unit */
--rhythm-base: 1.5rem;
/* Spacing scale based on rhythm */
--space-xs: calc(var(--rhythm-base) * 0.25);
--space-sm: calc(var(--rhythm-base) * 0.5);
--space-md: var(--rhythm-base);
--space-lg: calc(var(--rhythm-base) * 2);
--space-xl: calc(var(--rhythm-base) * 3);
}
/* Apply rhythm to typography */
p {
line-height: var(--rhythm-base);
margin-bottom: var(--space-md);
}
h2 {
margin-top: var(--space-lg);
margin-bottom: var(--space-sm);
}
ul, ol {
margin-bottom: var(--space-md);
}
By basing all spacing on multiples of --rhythm-base, you create predictable, harmonious spacing throughout your design.
Vertical Rhythm Visualizer
Toggle the baseline grid to see how elements align to a consistent vertical rhythm. When properly implemented, all text baselines and spacing align to the grid, creating visual harmony.
Vertical Rhythm Example
Vertical rhythm maintains consistent spacing relationships between elements. When you toggle the baseline grid, you can see how all text and spacing aligns to a regular interval.
Benefits of Vertical Rhythm
A consistent vertical rhythm creates visual harmony and makes content easier to scan. All spacing decisions become predictable because they follow a mathematical system.
- Creates visual consistency across the design
- Makes spacing decisions predictable and systematic
- Improves readability through consistent flow
- Establishes a professional, polished appearance
Notice how margins, line heights, and spacing all align to the baseline grid when properly implemented.
Responsive Typography
Typography must adapt to different screen sizes, viewport dimensions, and user preferences. Modern CSS provides powerful tools for creating fluid, responsive type systems that work across all devices.
Fluid Typography with clamp()
The clamp() function creates fluid typography that scales smoothly between minimum and maximum sizes based on viewport width. This eliminates the need for multiple media queries while ensuring text remains readable on all devices.
:root {
/* Fluid typography using clamp() */
--font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--font-size-lg: clamp(1.125rem, 1rem + 0.75vw, 1.5rem);
--font-size-xl: clamp(1.25rem, 1.1rem + 1vw, 2rem);
--font-size-2xl: clamp(1.5rem, 1.2rem + 1.5vw, 3rem);
--font-size-3xl: clamp(2rem, 1.5rem + 2.5vw, 4rem);
}
/* Typography scales automatically */
p { font-size: var(--font-size-base); }
h4 { font-size: var(--font-size-lg); }
h3 { font-size: var(--font-size-xl); }
h2 { font-size: var(--font-size-2xl); }
h1 { font-size: var(--font-size-3xl); }
The clamp(MIN, PREFERRED, MAX) function sets a minimum size, a preferred size that scales with viewport width, and a maximum size. Text grows smoothly as the viewport expands but never becomes too small or too large.
Responsive Line Height and Spacing
Line height and spacing should also adapt to screen size. Smaller screens often benefit from slightly tighter spacing to maximize content visibility, while larger screens can afford more generous spacing.
:root {
--line-height: 1.5;
--paragraph-spacing: 1rem;
}
@media (min-width: 768px) {
:root {
--line-height: 1.6;
--paragraph-spacing: 1.5rem;
}
}
@media (min-width: 1024px) {
:root {
--line-height: 1.75;
--paragraph-spacing: 2rem;
}
}
p {
line-height: var(--line-height);
margin-bottom: var(--paragraph-spacing);
}
Complete Typography System Example
Here is a complete typography system that combines all the concepts covered: custom properties for organization, modular scale for harmony, proper measure, vertical rhythm, and responsive sizing with clamp().
:root {
/* Font families */
--font-family-sans: 'Inter Variable', system-ui, sans-serif;
--font-family-serif: Georgia, serif;
/* Modular scale base and ratio */
--scale-ratio: 1.25;
--font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
/* Generated scale using calc() and clamp() */
--font-size-sm: calc(var(--font-size-base) / var(--scale-ratio));
--font-size-lg: clamp(1.125rem, 1rem + 0.75vw, 1.5rem);
--font-size-xl: clamp(1.25rem, 1.1rem + 1vw, 2rem);
--font-size-2xl: clamp(1.5rem, 1.2rem + 1.5vw, 3rem);
--font-size-3xl: clamp(2rem, 1.5rem + 2.5vw, 4rem);
/* Line heights */
--line-height-tight: 1.2;
--line-height-normal: 1.5;
--line-height-relaxed: 1.75;
/* Vertical rhythm */
--rhythm-base: 1.5rem;
--space-xs: calc(var(--rhythm-base) * 0.25);
--space-sm: calc(var(--rhythm-base) * 0.5);
--space-md: var(--rhythm-base);
--space-lg: calc(var(--rhythm-base) * 2);
--space-xl: calc(var(--rhythm-base) * 3);
/* Measure */
--measure-narrow: 45ch;
--measure-normal: 66ch;
--measure-wide: 80ch;
}
/* Base typography */
body {
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
color: oklch(0.2 0.02 250);
}
/* Headings */
h1, h2, h3, h4, h5, h6 {
font-weight: 700;
line-height: var(--line-height-tight);
margin-top: var(--space-lg);
margin-bottom: var(--space-sm);
}
h1 {
font-size: var(--font-size-3xl);
max-width: var(--measure-narrow);
}
h2 {
font-size: var(--font-size-2xl);
max-width: var(--measure-narrow);
}
h3 {
font-size: var(--font-size-xl);
max-width: var(--measure-normal);
}
h4 {
font-size: var(--font-size-lg);
}
/* Body text */
p {
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
max-width: var(--measure-normal);
margin-bottom: var(--space-md);
}
/* Long-form content */
article p {
line-height: var(--line-height-relaxed);
}
/* Lists */
ul, ol {
max-width: var(--measure-normal);
margin-bottom: var(--space-md);
padding-left: var(--space-md);
}
li {
line-height: var(--line-height-normal);
margin-bottom: var(--space-xs);
}
/* Small text */
small, .text-small {
font-size: var(--font-size-sm);
}
Typography Best Practices
-
Use system fonts as fallbacks: Always provide fallback fonts in case custom fonts fail to load. System fonts like
system-uiensure text remains readable. -
Optimize font loading: Use
font-display: swapto prevent invisible text, and consider preloading critical fonts with<link rel="preload">. - Choose appropriate ratios: Smaller ratios (1.125 to 1.25) work well for UI and short content. Larger ratios (1.5 to 1.618) create drama suitable for marketing and editorial designs.
-
Maintain readable measure: Keep line length between 45 and 75 characters for body text. Use
chunits for measure to ensure it adapts with font size. - Increase line height for longer lines: Body text needs more line height than headings. Long-form content benefits from even more generous spacing.
- Establish vertical rhythm: Base all spacing on multiples of a rhythm unit to create visual harmony throughout your design.
-
Make typography responsive: Use
clamp()for fluid sizing that adapts smoothly across viewport sizes without harsh breakpoints. - Test with real content: Typography systems should be tested with actual content, not lorem ipsum. Real text reveals issues with hierarchy, spacing, and readability.
Check Your Understanding
A student just completed comprehensive typography training covering font loading with @font-face and variable fonts, modular scales using mathematical ratios, measure (optimal line length of 45-75 characters), line height and vertical rhythm, and responsive typography with clamp(). They learned how to use custom properties to organize typography systems, how to calculate proportional scales, and how to make typography adapt to different screen sizes.\n They are analyzing a typography implementation to identify strengths and areas for improvement. Review their analysis and provide specific feedback. Check whether they recognized issues with measure, line height, vertical rhythm, scale relationships, or responsive behavior. Common mistakes include not understanding why certain measures are problematic, missing opportunities for custom properties, or not recognizing when typography is not responsive. Guide them to reconsider specific typography principles rather than giving direct answers.
/**
* Analyze this typography system and identify:
* 1. What typography principles are being violated?
* 2. What improvements would you recommend?
* 3. How would you reorganize this using custom properties?
*
* Consider: scale, measure, line height, rhythm, responsiveness
*/
body {
font-family: Arial, sans-serif;
font-size: 16px;
line-height: 1.2;
}
h1 { font-size: 48px; }
h2 { font-size: 36px; }
h3 { font-size: 28px; }
h4 { font-size: 20px; }
p {
font-size: 16px;
line-height: 1.2;
margin-bottom: 10px;
}
article p {
max-width: 100%;
}
Looking Ahead
You now have a complete foundation in typography fundamentals. In the next assignment, you will implement a full typographic system with a modular scale, proper measure and vertical rhythm, and responsive sizing. These typography principles will be essential throughout the rest of the course as you build complete design systems and component libraries. Good typography is not just about making text look nice; it is about creating readable, accessible, and harmonious user experiences.