Color Mode

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 text

Measure: 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

Check Your Understanding

Apply your typography knowledge to analyze a type system. Identify what works well and what could be improved, considering scale, measure, rhythm, and responsiveness.


        /**
         * 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.