The Conversion Formula
One formula covers 99% of cases:
rem = px / 16
px = rem * 16
The 16 is the browser's default root font size. Every browser ships with html { font-size: 16px } by default, and 1rem equals that root size. So 16px = 1rem, 24px = 1.5rem, 8px = 0.5rem, and so on.
Full Conversion Table
| Pixels | REM | Common Usage |
|---|---|---|
| 1px | 0.0625rem | Hairline borders (usually keep as px) |
| 2px | 0.125rem | Borders, outlines |
| 4px | 0.25rem | Tight spacing, micro gaps |
| 6px | 0.375rem | Small padding |
| 8px | 0.5rem | Standard small spacing unit |
| 10px | 0.625rem | Labels, captions |
| 12px | 0.75rem | Small text, badges |
| 14px | 0.875rem | Secondary body text |
| 16px | 1rem | Default body text (the baseline) |
| 18px | 1.125rem | Enlarged body / lead paragraphs |
| 20px | 1.25rem | Subheadings |
| 24px | 1.5rem | H3, generous padding |
| 28px | 1.75rem | H2 small |
| 32px | 2rem | H2, large section gaps |
| 40px | 2.5rem | H1 mobile |
| 48px | 3rem | H1 small desktop |
| 56px | 3.5rem | Hero headline |
| 64px | 4rem | Large hero / display |
| 80px | 5rem | Oversized display |
| 96px | 6rem | Huge display text |
Why REM Exists: Accessibility
The whole reason to prefer rem over px for typography: users can change their browser's default font size. In Chrome, go to Settings → Appearance → Font size and set it to "Large" or "Very Large." That multiplies the root font size from 16px to 20px, 24px, or even 32px.
If your site uses rem-based typography, everything scales proportionally — the user reading with vision impairment sees a genuinely larger interface. If your site uses pixel-based typography, their setting does nothing, and you've built something they can't comfortably read.
This is an accessibility requirement under WCAG 1.4.4 (Resize Text) — text must be resizable to 200% without loss of content or functionality. REM makes this trivial; pixel-only CSS usually violates it.
REM vs EM: The Critical Difference
Both are relative, but to different references:
- REM is relative to the root element (
<html>).1remis always the same size across your page. - EM is relative to the current element's font size.
1eminside a 24px heading equals 24px; inside a 12px caption it equals 12px.
This matters because EMs compound. If you nest font-size: 1.2em inside font-size: 1.2em inside font-size: 1.2em, the innermost text is 1.728× the size, not 1.2× — the kind of bug that breaks nested menus and nested lists.
When to Use Each Unit
| Use Case | Recommended Unit | Why |
|---|---|---|
| Font sizes (typography) | rem | Accessibility — respects user's zoom preference |
| Padding and margin | rem | Scales proportionally with text size |
| Component-internal spacing | em | Scales with the component's own font size |
| Borders (1–2px) | px | Pixel-perfect — rem rounding can make them disappear |
| Box shadows | px | Scaling shadows looks weird; fixed feels right |
| Media query breakpoints | em or px | em respects user zoom in media queries |
| SVG stroke widths | px | SVGs aren't affected by root font scaling |
| Line heights | unitless (e.g. 1.5) | Inherits cleanly across nested elements |
The 62.5% Trick (and Why It's Controversial)
You'll sometimes see this at the top of a stylesheet:
html {
font-size: 62.5%;
}
This makes 1rem = 10px instead of 16px, simplifying math: 1.4rem = 14px, 2.4rem = 24px. Popular in the 2010s.
Don't do this today. It breaks user-zoom expectations — when a user sets their browser to "Large" (20px), your baseline becomes 12.5px instead of 20px. The whole accessibility benefit of rem disappears. Stick with the default 16px root and embrace the decimals (or use a Sass function to auto-convert).
Modern Alternative: clamp() for Fluid Typography
Modern CSS can go beyond static rem values with clamp(min, preferred, max) for typography that scales smoothly across viewport sizes:
h1 {
/* min 2rem, scales with viewport, caps at 4rem */
font-size: clamp(2rem, 5vw, 4rem);
}
p {
/* body text from 1rem to 1.125rem based on viewport */
font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
}
This removes the need for most media queries for typography. Pair with rem values inside the clamp() call to preserve accessibility.
Frequently Asked Questions
- Is it OK to use px at all?
- Yes — for things that shouldn't scale with text: borders (especially 1px hairlines), box-shadow offsets, and SVG stroke widths. The accessibility rule is specifically about readable content, not visual decoration.
- What's the difference between rem and % for font-size?
- On the root
<html>element, they're identical:100% = 1rem = 16px. Elsewhere,%is relative to the parent's font-size (like em), whileremis relative to the root. Use rem unless you specifically want inheritance. - Do I need to convert every px in my CSS?
- No. Typography, padding, and margin should be rem. Borders, shadows, and component details can stay as px. Don't refactor aggressively — a partial migration (typography first) captures 90% of the accessibility benefit.
- What about viewport units like vw and vh?
- Useful for full-screen layouts (hero sections, full-viewport images) but dangerous for typography alone — they don't respect user zoom. Use inside
clamp()with rem values to get scaling that still respects accessibility. - Can I use rem in media queries?
- Use
emin media queries, notrem— this is a known quirk. When a user zooms,em-based media queries update (meaning your breakpoints shift), while rem-based ones in some older browsers may not.@media (min-width: 48em)is the accessibility-friendly pattern for a 768px breakpoint.