Skip to content

Typography System β€” Accessible Fonts, Sizes, and Spacing

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Typography System. We cover key concepts, practical examples, and best practices to help you master this topic.

An accessible typography system provides minimum 16px body text, line height of 1.5 to 2.0, clear heading hierarchy with adequate contrast, readable font choices, and responsive scaling for all screen sizes.

What You'll Learn

You will learn how to build a typography system that prioritizes readability, how to define type scales with Accessibility in mind, and how to ensure your typography tokens produce accessible text.

Why It Matters

Typography is the foundation of content readability. If the typography system produces text that is too small, too dense, or low contrast, every page built with it will be difficult to read for users with visual and cognitive disabilities.

Real-World Use

DodaKit's typography system starts at 16px body text with 1.6 line height. Heading sizes use a 1.25 ratio scale. All sizes use rem units for browser zoom compatibility. A readability mode increases line height to 2.0.

flowchart TD
  A[Typography System] --> B[Size Scale]
  A --> C[Line Height]
  A --> D[Font Family]
  A --> E[Heading Hierarchy]
  A --> F[Responsive Scaling]
  B --> G[16px base, 1.25 ratio]
  C --> H[1.5 to 2.0 range]
  D --> I[Sans-serif with fallback]
  E --> J[h1-h6 with weight]
  F --> K[rem units, clamp()]

Font Size Scale

Use a modular scale for font sizes. A 1.25 ratio (major third) starting at 16px produces a balanced scale: 16, 20, 25, 31, 39, 49 pixels. This ratio provides clear differentiation between levels.

Line Height

Define line height tokens for different text roles. Body text needs 1.5 to 2.0. Headings need 1.2 to 1.4. The line height should decrease as font size increases.

Font Family

Choose readable, widely available fonts. Sans-serif fonts like Inter, Segoe UI, or system fonts are preferred. Always provide a generic fallback.

// Typography scale generator
function generateAccessibleScale(baseSize, ratio, steps) {
  const scale = [];

  for (let i = 0; i < steps; i++) {
    const size = baseSize * Math.pow(ratio, i);

    let lineHeight;
    if (size <= 16) lineHeight = 1.8;
    else if (size <= 20) lineHeight = 1.6;
    else if (size <= 25) lineHeight = 1.4;
    else if (size <= 31) lineHeight = 1.3;
    else lineHeight = 1.2;

    const name = i === 0 ? 'body' :
                 i === 1 ? 'h4' :
                 i === 2 ? 'h3' :
                 i === 3 ? 'h2' :
                 i === 4 ? 'h1' :
                 `display-${i - 4}`;

    scale.push({
      name: name,
      sizePx: Math.round(size),
      sizeRem: Math.round(size / 16 * 100) / 100 + 'rem',
      lineHeight: lineHeight,
      recommendedFor: name === 'body' ? 'Body text' : `${name.toUpperCase()} headings`
    });
  }

  return scale;
}

const typographyScale = generateAccessibleScale(16, 1.25, 6);
console.table(typographyScale);

Expected output:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ (index) β”‚ name      β”‚ sizePx β”‚ sizeRemβ”‚ lineHeight  β”‚ recommendedFor   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 0       β”‚ body      β”‚ 16     β”‚ '1rem' β”‚ 1.8         β”‚ 'Body text'      β”‚
β”‚ 1       β”‚ h4        β”‚ 20     β”‚ '1.25r'β”‚ 1.6         β”‚ 'H4 headings'    β”‚
β”‚ 2       β”‚ h3        β”‚ 25     β”‚ '1.56r'β”‚ 1.4         β”‚ 'H3 headings'    β”‚
β”‚ 3       β”‚ h2        β”‚ 31     β”‚ '1.94r'β”‚ 1.3         β”‚ 'H2 headings'    β”‚
β”‚ 4       β”‚ h1        β”‚ 39     β”‚ '2.44r'β”‚ 1.2         β”‚ 'H1 headings'    β”‚
β”‚ 5       β”‚ display-1 β”‚ 49     β”‚ '3.06r'β”‚ 1.2         β”‚ 'Display heading'β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Heading Hierarchy

Use semantic heading levels h1 through h6. Do not skip levels. Ensure heading sizes are visually distinct. The heading level in HTML must match the visual hierarchy.

Responsive Typography

Use rem units so text scales with browser zoom. Use clamp() for fluid typography that scales between minimum and maximum sizes based on viewport width.

/* Accessible typography system tokens */
:root {
  /* Base settings */
  --ds-font-body: 'Inter', 'Segoe UI', system-ui, sans-serif;
  --ds-font-heading: 'Inter', 'Segoe UI', system-ui, sans-serif;

  /* Font sizes β€” modular scale 1.25 starting at 16px */
  --ds-text-xs: 0.75rem;    /* 12px β€” only for labels */
  --ds-text-sm: 0.875rem;   /* 14px β€” secondary text */
  --ds-text-md: 1rem;       /* 16px β€” body */
  --ds-text-lg: 1.25rem;    /* 20px β€” h4 */
  --ds-text-xl: 1.563rem;   /* 25px β€” h3 */
  --ds-text-2xl: 1.953rem;  /* 31px β€” h2 */
  --ds-text-3xl: 2.441rem;  /* 39px β€” h1 */
  --ds-text-4xl: 3.052rem;  /* 49px β€” display */

  /* Line heights */
  --ds-leading-tight: 1.2;
  --ds-leading-snug: 1.4;
  --ds-leading-normal: 1.6;
  --ds-leading-relaxed: 1.8;
  --ds-leading-loose: 2.0;

  /* Fluid typography example */
  --ds-text-fluid-h1: clamp(1.953rem, 1.5rem + 2vw, 3.052rem);
  --ds-text-fluid-body: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
}

/* Usage example */
body {
  font-family: var(--ds-font-body);
  font-size: var(--ds-text-md);
  line-height: var(--ds-leading-normal);
}

h1 {
  font-family: var(--ds-font-heading);
  font-size: var(--ds-text-fluid-h1);
  line-height: var(--ds-leading-tight);
  font-weight: 700;
}

Common Mistakes

1. Body Text Below 16px

Design systems often set body text at 14px or even 12px. This is too small for readable content.

2. Tight Line Height on Body Text

Line height below 1.5 makes body text dense and difficult to read. Always use at least 1.5 for body.

3. Skipping Heading Levels

Using h1 then h3 without h2 violates semantic hierarchy. Ensure heading levels are sequential.

4. Using px Units

Px units prevent browser zoom from scaling text. Use rem units for all text sizes.

5. Italic or Light Weight Fonts for Body

Light (300) or italic body text is harder to read. Use regular (400) weight for body.

6. No Fallback Font

Custom fonts may not load. Always provide a system font fallback.

7. Heading Sizes Too Similar

Headings that are visually similar do not convey hierarchy. Ensure at least 1.25 ratio between levels.

Practice Questions

1. What is the minimum body text size for an accessible typography system?

16px (1rem). Smaller text is difficult to read for users with visual and cognitive disabilities.

2. What line height range should body text use?

1.5 to 2.0. Below 1.5 is too dense; above 2.0 has too much separation between lines.

3. Why should heading sizes not be skipped?

Skipping heading levels (h1 to h3 without h2) breaks the semantic hierarchy that screen readers rely on.

4. What CSS unit should be used for font sizes and why?

rem units. They respect browser zoom settings and allow users to scale text.

5. Challenge: Create a typography scale with 6 levels. Specify font size (in rem), line height, font weight, and usage for each level.

FAQ

Can I use px for font sizes if I also provide a zoom control?

Use rem instead. Relying on a custom zoom control instead of browser zoom is less reliable and may not cover all browsers.

What font is best for accessibility?

Sans-serif fonts like Inter, Segoe UI, Arial, or system fonts. Avoid decorative, script, or handwriting fonts for body text.

How do I handle long line lengths?

Set a max-width on text containers. 35 to 45em is recommended for body text.

Should I use justified text alignment?

No. Justified text creates uneven word spacing that makes reading harder. Use left alignment.

How many heading levels should a design system define?

Define all 6 levels (h1-h6). Even if rarely used, they should be available for accessibility.

Mini Project

Create a typography system specification with 6 sizes, 5 line height values, and 3 font families. Include responsive tokens using clamp() and rem units. Validate that body text starts at 16px.

What's Next

Learn about Spacing and Layout for accessible design systems. Then explore Component Library a11y patterns.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro