Article — PX to EM Converter
PX to EM converter: CSS units for responsive typography
CSS pixels, em and rem all measure length but behave differently. 1 rem = 16 px by default, since browsers ship with a 16 px root font size. The conversion rem = px / 16 is the workhorse formula. em is relative to the parent font-size, not the root.
The 16 px default isn't arbitrary. It matches the WCAG-recommended minimum body text size for accessibility. Overriding it on <html> breaks user font-size preferences and was a major accessibility regression in early "responsive" design. Modern best practice keeps the root at 16 px and uses rem for everything.
PX vs EM vs REM
The CSS pixel is an absolute length unit defined as 1/96 of an inch. On a high-DPI display, one CSS pixel maps to multiple device pixels — but to your CSS it's still 1 px. em is relative to the parent element's font-size. rem (root em) is relative only to the root <html> element's font-size. Both behave the same when the parent and root match.
The practical difference shows up under nesting. A 1.5em font-size inside a 1.5em font-size produces 2.25× the root. A 1.5rem font-size inside a 1.5rem font-size is still 1.5rem of the root. rem stays predictable; em compounds.
The "em" name comes from typography — the historical em-quad was a metal block as wide as the capital M of the current type size. Modern CSS em inherits the relativity but ditches the M-shape.
PX to REM formula and base size
The conversion is straightforward: rem = px / base. With the browser default base of 16 px, 12 px becomes 0.75 rem, 24 px becomes 1.5 rem, 32 px becomes 2 rem. Some teams use a 10 px base via html { font-size: 62.5%; } to make the math cleaner (24 px = 2.4 rem). This works but reduces accessibility — see the warning below.
- 10 px = 0.625 rem (base 16) or 1 rem (base 10)
- 12 px = 0.75 rem (base 16) — small UI text
- 14 px = 0.875 rem — secondary body text
- 16 px = 1 rem — body text default
- 18 px = 1.125 rem — comfortable reading
- 24 px = 1.5 rem — h3 / section title
- 32 px = 2 rem — h2 / page title
- 48 px = 3 rem — h1 / hero heading
When to use EM (not REM)
em earns its keep for component-internal spacing. A button styled with font-size: 1rem; padding: 0.5em 1em; scales its padding with its own text size. Make the button larger (font-size: 1.5rem) and the padding grows proportionally. With rem padding, the padding stays fixed while the text grows — usually not what you want for a button.
The rule of thumb: rem for global rhythms, em for component-internal proportions. Margin between sections? rem. Padding inside a card whose font-size might change? em. Border thickness? px (borders should stay crisp at exact pixel widths).
PX to PT for print
Points (pt) are a print unit: 1 pt = 1/72 inch. CSS supports pt but you should only use it inside @media print. The conversion is fixed: pt = px × 72 / 96, so 16 px = 12 pt. On screen, browsers ignore the historical 72 DPI assumption and just scale pt as if it were 1.333 px.
For a print stylesheet, 10-12 pt is comfortable body text, 14-18 pt for subheadings. Browser print engines size pt to physical inches when printing, so a 12 pt heading prints at 12/72 = 1/6 inch tall regardless of screen size.
Accessibility: EM/REM and WCAG
WCAG 2.1 Success Criterion 1.4.4 (Resize Text) requires that text scale up to 200% without loss of content. Pixel-sized text breaks this: it ignores the user's browser font-size setting. rem-sized text scales because it's relative to the root, which the user controls.
Setting html { font-size: 10px } or 62.5% overrides the user's accessibility preferences. If they bumped their browser default to 20 px for readability, your stylesheet just shrunk it back to 10. Many "10 px base" tutorials are outdated. Stick to the default 16 px and use rem multipliers.
The nested EM trap
em is relative to the parent, not the grandparent. A list with font-size: 1.5em inside a section with font-size: 1.5em renders at the root × 1.5 × 1.5 = 2.25× the root. Three levels of 1.5em compound to 3.375×. This was a major source of bugs in 2010-era CSS before rem went mainstream.
Use rem for typography to avoid this entirely. Reserve em for properties that should track the element's own font size (line-height, padding, margin in some component contexts).
Fluid typography with clamp()
The modern CSS function clamp(min, preferred, max) lets type size scale fluidly with the viewport. A heading written as font-size: clamp(1.5rem, 4vw, 3rem); stays at 1.5 rem on small screens, scales with 4% of the viewport width in between, and caps at 3 rem on wide screens. No media queries needed.
Build a fluid type scale once and reuse it. --fs-h1: clamp(2rem, 5vw + 1rem, 4rem); as a CSS custom property lets you set h1 size everywhere with one declaration. Tweak the slope and clamp values to taste.
Common PX to EM mistakes
The most common mistake is treating em and rem as interchangeable. They produce the same value only when parent equals root. Inside a nested or sized element, they diverge — sometimes by surprising amounts. The second mistake is overriding the root font-size to make math cleaner; modern CSS doesn't need this hack and it breaks accessibility.
The third mistake is using px for typography while using rem for spacing. This couples the visual size to the device but decouples the rhythm from the user's font-size preference. Pick a unit per category and stay consistent: rem for type and spacing, em for component-internal sizes, px for borders and hairlines.
A fourth subtler pitfall is media-query breakpoints in px. If you write @media (min-width: 768px) and the user has bumped their browser font-size from 16 to 20 px, the breakpoint still triggers at 768 device pixels — possibly cutting off content that the user can't read at their preferred size. Use em-based breakpoints (@media (min-width: 48em)) so layouts respond to text-size preferences as well as viewport width.