If you have ever wondered whether to write padding: 16px or padding: 1rem, this guide is for you. We'll cover what rem actually means, why accessibility-conscious developers reach for it, the exact conversion formula, and how to migrate an existing stylesheet without breaking your design.
Need to convert a value right now?
Open Px to Rem Converter →The conversion formula
One formula, no surprises:
rem = px ÷ root_font_size
px = rem × root_font_size
The browser's default root font size is 16px. So the math people memorise:
16px → 1rem
24px → 1.5rem
32px → 2rem
8px → 0.5rem
14px → 0.875rem
If your stylesheet sets html { font-size: ... } to anything other than 16px, divide by that value instead.
What rem actually is
rem stands for "root em". It is a length unit relative to the font size of the root element — the <html> element. The browser sets a default of 16px on html, but the user can change this in their browser settings, and your CSS can change it too.
Compare it to its cousin em:
emis relative to the parent element's font size — and compounds when nested. A1.2emheading inside a1.2emcontainer is actually 1.44× the parent's parent size.remis relative to the root only — no compounding.1remis always the same size everywhere on the page.
This is why most modern design systems standardise on rem: a single source of truth that scales the entire UI when needed.
Why rem beats px for accessibility
Open Chrome's settings → Appearance → Font size. You'll see options for "Very small", "Small", "Medium", "Large", "Very large". This setting changes the default font size of the html element. A user with low vision may set it to "Very large" (typically 24px instead of 16px).
Now imagine your button:
/* Pixel-based — ignores user preference */
.button { padding: 12px 24px; font-size: 16px; }
/* Rem-based — scales with user preference */
.button { padding: 0.75rem 1.5rem; font-size: 1rem; }
For a user with the "Very large" setting, the rem version's padding becomes 18px 36px and font becomes 24px — the entire button grows proportionally. The pixel version stays at 12px 24px, with text the user can barely read inside an undersized button.
The WCAG 2.2 — Resize Text success criterion expects content to scale up to 200% without loss of content or functionality. Rem-based layouts pass this naturally; pixel-based layouts often fail.
The 62.5% trick — convenient but controversial
You'll often see this in production CSS:
html { font-size: 62.5%; }
/* 62.5% of 16px = 10px */
body { font-size: 1.6rem; } /* = 16px */
.card { padding: 2.4rem; } /* = 24px */
Setting the root to 62.5% makes 1rem equal 10px, and the math becomes trivial: 1.6rem is 16px, 2.4rem is 24px, 0.8rem is 8px. Many designers love this because they can think in pixels but write rems.
The problem: you've overridden the user's browser font size preference. A user who set their browser to 20px now gets 20px × 62.5% = 12.5px as the root — smaller than they wanted. The accessibility benefit of rem is partially defeated.
The fix: always restore body text to a sensible size: body { font-size: 1.6rem; } means default text is 16px-equivalent of their root, not yours. The 62.5% only affects sizes you explicitly set. This is a reasonable compromise — but plain rem with no 62.5% override is the purest path.
When to still use px
Don't convert blindly. Some things genuinely belong in pixels:
- Borders —
border: 1px solid #cccstays a hairline at any zoom level.0.0625remrounds inconsistently across browsers and can look fuzzy. - Box shadows — Same idea. A
0 2px 4px rgba(0,0,0,0.1)shadow has a designed look that doesn't benefit from scaling. - Outline width — Focus rings and outlines are usually defined as 2px or 3px for visual consistency.
- Image dimensions — When you need an image to fit a known pixel grid (favicons, sprites, app icons), use px or no unit at all.
- Media query breakpoints — Modern recommendation is
em(which respects browser zoom), butpxis still common and acceptable.
Migrating an existing stylesheet
You don't have to convert everything at once. A pragmatic migration:
- Convert font sizes first. They have the biggest accessibility impact.
/* Before */ h1 { font-size: 32px; } p { font-size: 16px; } /* After */ h1 { font-size: 2rem; } p { font-size: 1rem; } - Convert spacing — padding, margin, gap. These also benefit from scaling.
/* Before */ .card { padding: 24px; margin-bottom: 16px; } /* After */ .card { padding: 1.5rem; margin-bottom: 1rem; } - Leave borders, shadows, and 1–2px decorative widths alone. They are fine as px.
- Test with browser zoom + custom font size. Set Chrome to "Very large" font and zoom to 200%. Your layout should remain usable.
For large stylesheets, our Px to Rem Converter has a bulk mode — paste your CSS, click "Convert px → rem", and review the output before committing.
Common conversions reference
Assuming the standard 16px root:
| Pixels | Rem | Common use |
|---|---|---|
| 8px | 0.5rem | Tight spacing, small gaps |
| 12px | 0.75rem | Captions, helper text |
| 14px | 0.875rem | Secondary text, labels |
| 16px | 1rem | Body text (default) |
| 18px | 1.125rem | Slightly larger body |
| 20px | 1.25rem | Lead paragraphs, h4 |
| 24px | 1.5rem | Card padding, h3 |
| 32px | 2rem | Section spacing, h2 |
| 48px | 3rem | Large headings, h1 |
| 64px | 4rem | Hero text, big margins |
Sass / SCSS helpers
If you write Sass, a small function turns the conversion into a one-liner:
// _functions.scss
@function rem($px, $base: 16) {
@return ($px / $base) * 1rem;
}
// usage
.card {
padding: rem(24); // → 1.5rem
font-size: rem(14); // → 0.875rem
}
Note: in modern Sass (1.65+), division uses math.div():
@use "sass:math";
@function rem($px, $base: 16) {
@return math.div($px, $base) * 1rem;
}
CSS-only with custom properties
You can do the same in plain CSS using a custom property:
:root {
--base-font-size: 16;
}
.card {
/* calc with unit-less variable */
padding: calc(24 / var(--base-font-size) * 1rem);
}
This is verbose but eliminates the build step. Most teams just compute the rem values upfront and write them directly.
Need to convert a stylesheet? Use the free Px to Rem Converter →
Frequently Asked Questions
What is rem in CSS?
rem stands for 'root em' — it is a relative CSS unit based on the font size of the root element (html). The browser default is 16px, so 1rem equals 16px unless the user or developer changes the root font size. Unlike em, rem is always relative to the root, not the parent element, making it predictable in nested layouts.
How do I convert px to rem?
The formula is: rem = px ÷ root_font_size. With the default 16px root size: 16px = 1rem, 24px = 1.5rem, 32px = 2rem. If you set html { font-size: 62.5% } (making 1rem = 10px), the conversion becomes: 16px = 1.6rem, 24px = 2.4rem — easier mental arithmetic but requires resetting body font size.
Why should I use rem instead of px for font sizes?
Using rem for font sizes respects user browser preferences. When a user increases their browser default font size for accessibility (e.g. vision impairment), rem-based layouts scale correctly. Pixel values are fixed and override the user's preference, which can make text unreadably small. WCAG accessibility guidelines recommend rem over px for font sizes.
When is it still OK to use px in CSS?
Pixels are fine for borders (border: 1px solid), box shadows, and media query breakpoints — values that should not scale with font size. They are also appropriate for icons and decorative elements where exact pixel rendering matters. Avoid px for font-size, line-height, padding, and margin when accessibility is a concern.