PX to REM: The Developer's Guide to Scalable Typography

Learn why rem units improve accessibility, how to calculate them, and best practices for responsive typography in CSS.

6 min read CSS · Accessibility · Typography 6 sections + FAQ

The choice between px and rem in CSS is not just a stylistic preference — it has direct consequences for accessibility, user control, and responsive design. Millions of users set a custom font size in their browser preferences, and a stylesheet written entirely in px ignores that setting completely.

This guide explains the mechanics of each unit, the formula for converting px to rem, and the practical rules for when to use each in a real-world CSS codebase.

Understanding CSS units (px, rem, em, vh)

CSS offers multiple length units for different use cases. px (pixels) is an absolute unit — 1px on a 96dpi screen corresponds to a physical pixel, but on high-DPI (Retina) displays it maps to multiple physical pixels. rem (root em) is a relative unit based on the font-size of the root element (<html>). em is a relative unit based on the font-size of the current element or its nearest ancestor with an explicit font-size. vh and vw are viewport-relative: 1vh = 1% of the viewport height. Each unit has appropriate and inappropriate use cases.

Free Tool PX to REM Converter Instantly convert pixel values to rem with any base size

Why px is problematic for accessibility

Browsers allow users to set a default font size in preferences (typically 16px by default, but users may set it to 20px, 24px, or larger). When you set font-size: 16px in CSS, this overrides the user's preference — the text will always be 16px regardless of what the user has configured. This violates WCAG 2.1 Success Criterion 1.4.4 (Resize Text), which requires that text can be resized up to 200% without loss of content or functionality. Rem-based typography respects the user's root font size and scales accordingly.

How rem works (root font-size)

The rem unit is always relative to the font-size of the <html> element. By default, browsers set this to 16px. So 1rem = 16px, 1.5rem = 24px, 0.875rem = 14px. If a user increases their browser font size to 20px, then 1rem = 20px — all rem-based values scale proportionally. Never set font-size on <html> in pixels (e.g., html { font-size: 16px }) because this defeats the purpose — it resets the base to a fixed value regardless of user preferences. If you need to change the base, use a percentage: html { font-size: 112.5% } sets the base to 18px on a default 16px browser.

Free Tool Color Contrast Checker Check WCAG 2.1 contrast ratios alongside font size accessibility

PX to REM formula

The formula is simple: rem = px / base-font-size. With the default 16px base: 12px = 0.75rem, 14px = 0.875rem, 16px = 1rem, 18px = 1.125rem, 24px = 1.5rem, 32px = 2rem. In CSS preprocessors (Sass, Less), you can define a function. In modern CSS, custom properties and calc() can automate this without a preprocessor.

/* Sass function */
@function rem($px) {
  @return #{$px / 16}rem;
}

/* Usage */
font-size: rem(18); /* → 1.125rem */

/* Pure CSS alternative */
:root {
  --base: 16;
}

.text {
  /* Manual calc — not dynamic */
  font-size: calc(18 / var(--base) * 1rem);
}

When to use rem vs em vs px

Use rem for global typography (body text, headings, labels) and for spacing that should scale with the user's font size preference. Use em for component-level spacing that should be proportional to the component's own font size (padding inside a button, for example — so the button scales uniformly when its font-size changes). Use px for borders, shadows, and layout elements that should not scale with text (1px borders should stay 1px regardless of font size). Use viewport units (vh, vw, vmin, vmax) for layout elements that should fill or relate to the viewport, not typography.

CSS custom properties for rem base

A common pattern is to set a CSS custom property for the base font size to enable easy global adjustment. Set font-size as a percentage on <html> to respect user preferences, then use rem throughout. The clamp() function creates fluid typography that scales between minimum and maximum values based on viewport width, without media query breakpoints. This combines the accessibility benefits of rem with fluid responsive behavior.

/* Accessible base — respects browser preference */
html {
  font-size: 100%; /* = browser default (usually 16px) */
}

body {
  font-size: 1rem;    /* 16px at default */
}

h1 {
  font-size: 2rem;    /* 32px at default, scales with user prefs */
}

/* Fluid typography with clamp */
.hero-title {
  font-size: clamp(1.5rem, 4vw, 3rem);
  /* min 24px, max 48px, fluid between */
}
Free Tool Color Palette Generator Build accessible color palettes alongside your typographic system

Frequently Asked Questions

What is the difference between px, rem, and em in CSS? +
px is an absolute unit that maps to device pixels (or logical pixels on high-DPI screens). rem is relative to the root element () font-size. em is relative to the current element's own font-size (or nearest ancestor with one). rem is preferred for typography and spacing because it respects user browser preferences for font size.
How do I convert px to rem in CSS? +
Divide the pixel value by the base font size (usually 16px): rem = px / 16. Examples: 12px = 0.75rem, 18px = 1.125rem, 24px = 1.5rem, 32px = 2rem. The PixCode px-to-rem tool automates this conversion for any base size.
Why is using px for font-size bad for accessibility? +
When font-size is set in px, it overrides the user's browser font-size preference. Users who need larger text (due to visual impairment or preference) cannot override px-based font sizes by adjusting their browser settings. WCAG 2.1 criterion 1.4.4 requires text to be resizable to 200% without loss of content or functionality.
What is 1rem in pixels? +
1rem equals the font-size of the element. In most browsers, the default is 16px, so 1rem = 16px by default. If a user changes their browser font size to 20px, then 1rem = 20px. Never hardcode html { font-size: 16px } as this defeats the purpose — use html { font-size: 100% } instead to inherit the browser default.
Should I use rem or em for padding and margin? +
Use rem for padding and margin that should scale with the global font size (page-level whitespace, section gaps). Use em for component-internal spacing that should scale proportionally with the component's font-size (e.g., button padding, list item spacing). This way, if you change a component's font-size, its internal padding adjusts automatically.
Can I use rem for layout (width, height, grid)? +
Technically yes, but it's generally not recommended for layout widths. Layout should typically use percentage, fr units (grid), or viewport units — not rem. Using rem for max-width (e.g., max-width: 60rem for a content column) is common and works well because it creates a readable line length that also scales with user font preferences.
Does the PixCode px-to-rem tool support custom base sizes? +
Yes. The PixCode PX to REM converter allows you to set any base font size (default 16px but configurable). It also shows the CSS output ready to paste and supports batch conversion of multiple values at once.