CSS & layout
PX to EM converter
Pixels to em and back, plus the compounding behaviour that makes em bite.
em is relative to the parent element's computed font size, not the root — so it compounds through nesting. Set the basis to whatever the parent actually resolves to.
Reference table
| Pixels | em |
|---|---|
| 1px | 0.0625em |
| 2px | 0.125em |
| 4px | 0.25em |
| 6px | 0.375em |
| 8px | 0.5em |
| 10px | 0.625em |
| 11px | 0.6875em |
| 12px | 0.75em |
| 13px | 0.8125em |
| 14px | 0.875em |
| 15px | 0.9375em |
| 16px | 1em |
| 18px | 1.125em |
| 20px | 1.25em |
| 22px | 1.375em |
| 24px | 1.5em |
| 26px | 1.625em |
| 28px | 1.75em |
| 30px | 1.875em |
| 32px | 2em |
| 36px | 2.25em |
| 40px | 2.5em |
| 44px | 2.75em |
| 48px | 3em |
| 56px | 3.5em |
| 64px | 4em |
| 72px | 4.5em |
| 80px | 5em |
| 96px | 6em |
| 112px | 7em |
| 128px | 8em |
| 160px | 10em |
| 192px | 12em |
| 256px | 16em |
The arithmetic is identical to rem. What you divide by isn’t, and that changes everything about how the unit behaves.
What em measures against
em resolves against the computed font size of the parent element, not the
root. 1.5em means “one and a half times whatever my parent turned out to be”,
and the answer moves depending on where the element sits in the tree.
Parent at the 16px default? 1.5em is 24px. Parent at 20px? The same declaration
is now 30px. Nothing in your CSS changed; the context did.
Put the parent’s real computed size into the basis field above. If you leave it at 16 out of habit you’ll get the rem answer wearing an em label.
The compounding trap
This is the behaviour that makes people swear off em entirely, and it’s worth seeing rather than being told about:
.card { font-size: 0.9em; }<div class="card"> <!-- 16 × 0.9 = 14.4px -->
<div class="card"> <!-- 14.4 × 0.9 = 12.96px -->
<div class="card"> <!-- 12.96 × 0.9 = 11.66px -->
Why is this so small?Every level multiplies again. Three levels of a completely reasonable 0.9em and
the text is 27% smaller than anyone intended. In rem all three would be the same
size, because rem never looks up the tree.
It isn’t a bug to be worked around. It’s the defining property of the unit, and now and then it’s precisely what you want.
When em is the better choice
Padding and spacing that should track the element’s own text is the strongest
case. A button with 0.75em 1.5em padding keeps its proportions whether it’s the
small variant or the large one: set the font size and the padding follows. Do
that in rem and you’re re-specifying padding at every size.
The same logic covers most component-internal spacing, anything that should scale
as a unit when one font size changes. letter-spacing and text-indent too,
since those are almost always meant to be proportional to the text they sit on.
For layout, page-level spacing, container widths and design-system font sizes, reach for rem instead. You want one predictable answer there regardless of nesting.
Most codebases settle on some version of rem for the page, em inside the component, and that’s a fine rule to start from.
The media query exception
Both units resolve against the browser’s default font size inside a @media
rule, ignoring whatever you set on html. They’re interchangeable there. Anyone
who has set 62.5% and expected their breakpoints to shift has run into this.
A note on finding the parent size
Devtools, Computed panel, font-size. Use that number, not whatever the parent’s
CSS declaration says, because the parent may well be sized in em itself and
you’d be starting the compounding problem one level early.
Related tools
- PX to REM converter Pixels to rem and back, at whatever root font size your project uses.
- PX to Tailwind converter Turn a pixel value into the Tailwind utility that produces it, and find out when there isn't one.
- LiveMarkup Paste HTML, CSS and JS, see it render instantly. No account, no project setup, nothing to save.