X Xerobit

REM-Based Typography — Scalable Font Sizes with rem Units

Using rem for font sizes creates accessible, scalable typography. Text inherits from the user's browser setting instead of a fixed pixel size. Here's how to set up rem-based...

Mian Ali Khalid · · 5 min read
Use the tool
Pixel to REM Converter
Convert px to rem, em, and percent — and vice versa. Configurable root font size. Bulk conversion mode for entire stylesheets.
Open Pixel to REM Converter →

Using rem for font sizes lets users control text size through browser settings. When a user sets their browser to 20px base font, everything sized in rem scales up proportionally — px values stay fixed.

Use the PX to REM Converter to convert pixel values to rem.

Why rem for typography

/* Fixed pixels — ignores user font settings: */
.text { font-size: 16px; }  /* Never changes */

/* rem — respects user preferences: */
.text { font-size: 1rem; }   /* Scales with browser setting */

A user who sets their browser to 20px base (common for low-vision users) sees:

  • 16px → remains 16px (too small for them)
  • 1rem → becomes 20px (respects their preference)

This is the core accessibility argument for rem typography.

Setting up the root font size

/* Common approach: 62.5% base makes 1rem = 10px at default: */
html {
  font-size: 62.5%;  /* 16px × 0.625 = 10px */
}

/* Now rem values are easy to calculate: */
h1 { font-size: 3.2rem; }    /* 32px */
h2 { font-size: 2.4rem; }    /* 24px */
body { font-size: 1.6rem; }  /* 16px */
small { font-size: 1.2rem; } /* 12px */

Caution: The 62.5% trick overrides user font-size settings because it’s percentage-based from the user’s set size. If the user sets 20px, the base becomes 12.5px, not 10px — still proportional.

/* Alternative: keep default root font size, use natural rem values */
html {
  /* No font-size override — use browser default (16px) */
}

h1 { font-size: 2rem; }      /* 32px */
h2 { font-size: 1.5rem; }    /* 24px */
p  { font-size: 1rem; }      /* 16px */
small { font-size: 0.875rem; } /* 14px */

This is the cleanest approach — no percentage tricks needed.

Type scale system

A modular type scale creates visual harmony by using consistent ratios between sizes:

:root {
  /* Base: 1rem = 16px (browser default) */
  --text-xs:   0.75rem;   /* 12px */
  --text-sm:   0.875rem;  /* 14px */
  --text-base: 1rem;      /* 16px */
  --text-lg:   1.125rem;  /* 18px */
  --text-xl:   1.25rem;   /* 20px */
  --text-2xl:  1.5rem;    /* 24px */
  --text-3xl:  1.875rem;  /* 30px */
  --text-4xl:  2.25rem;   /* 36px */
  --text-5xl:  3rem;      /* 48px */
  --text-6xl:  3.75rem;   /* 60px */
}

/* This is Tailwind's type scale */

h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
h4 { font-size: var(--text-xl); }
p  { font-size: var(--text-base); }
small { font-size: var(--text-sm); }

Fluid typography with clamp()

clamp() creates font sizes that scale smoothly between minimum and maximum:

h1 {
  font-size: clamp(1.75rem, 4vw, 3rem);
  /* Minimum: 1.75rem (28px)
     Preferred: 4% of viewport width
     Maximum: 3rem (48px) */
}

body {
  font-size: clamp(1rem, 1.2vw + 0.5rem, 1.25rem);
}

This scales from the minimum on small screens to the maximum on large screens without media queries.

Complete fluid type scale

:root {
  --text-sm:   clamp(0.8rem,   0.17vw + 0.76rem, 0.89rem);
  --text-base: clamp(1rem,     0.34vw + 0.91rem, 1.19rem);
  --text-lg:   clamp(1.25rem,  0.61vw + 1.1rem,  1.58rem);
  --text-xl:   clamp(1.56rem,  1vw + 1.31rem,    2.11rem);
  --text-2xl:  clamp(1.95rem,  1.56vw + 1.56rem, 2.81rem);
  --text-3xl:  clamp(2.44rem,  2.38vw + 1.85rem, 3.75rem);
}

Generated using Utopia’s type scale calculator.

Responsive typography with media queries

The simpler approach when fluid isn’t needed:

/* Mobile first: */
:root {
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --heading-1: 1.75rem;
  --heading-2: 1.5rem;
}

/* Tablet: */
@media (min-width: 768px) {
  :root {
    --heading-1: 2.25rem;
    --heading-2: 1.875rem;
  }
}

/* Desktop: */
@media (min-width: 1200px) {
  :root {
    --heading-1: 3rem;
    --heading-2: 2.25rem;
  }
}

h1 { font-size: var(--heading-1); }
h2 { font-size: var(--heading-2); }

Line height with unitless values

/* AVOID: px or rem line-height (doesn't scale with font size): */
p { line-height: 24px; }
p { line-height: 1.5rem; }

/* PREFER: unitless (scales with font-size automatically): */
p { line-height: 1.6; }       /* 1.6 × font-size */
h1 { line-height: 1.1; }      /* Tighter for headings */
.small-text { line-height: 1.4; }

Related posts

Related tool

Pixel to REM Converter

Convert px to rem, em, and percent — and vice versa. Configurable root font size. Bulk conversion mode for entire stylesheets.

Written by Mian Ali Khalid. Part of the Frontend & Design pillar.