Skip to content
Back to Blog
Tutorials

PX vs REM vs EM: The Complete CSS Units Guide

px vs rem vs em explained: what each CSS unit means, when to use rem for accessibility, the em compounding trap, and a per-property cheat sheet.

12 min read

PX vs REM vs EM: The Complete CSS Units Guide

Here is the short answer to px vs rem vs em, before any explanation. Use rem for almost all sizing: font sizes, padding, margins, gaps, border-radius, and breakpoints, because it scales with the reader’s browser font-size setting. Use px for the few things that should never scale, like a 1px border or a precise shadow offset. Use em for the rare local case where a value should grow with the element’s own font size, such as button padding that tracks the button’s text.

That rule covers 90% of decisions. The other 10% is where the trouble usually starts: the em compounding math that surprises everyone the first time, the media-query bug that breaks layouts on zoom, and the cases where px is actually the more accessible choice. The sections below cover all three, with runnable CSS for each, plus a per-property cheat sheet you can keep open while you write styles.

What px, rem, and em actually mean

Three units, three different reference points. That is the distinction.

px is an absolute unit. One px is one CSS pixel, and it stays that size no matter what surrounds it. border: 1px solid is one pixel, full stop. The catch is that “absolute” also means it ignores the user’s preferences, which we will get to below.

rem is relative to the root element’s font size. The root is <html>, and browsers set its font size to 16px by default. So 1rem equals 16px on a standard setup, everywhere on the page, regardless of nesting. That consistency is the appeal: one anchor value, no surprises.

em is relative to the font size of the current element (or its parent, for non-font-size properties). Because that reference changes as you nest elements, em values shift depending on context. The same 1.5em can resolve to 24px in one place and 30px in another.

The anchor to memorize is 16px = 1rem. If you internalize nothing else, internalize that. When you need to translate a specific value, the px to rem converter does the division against any base you choose.

px vs rem vs em at a glance

UnitRelative toScales with user font size?Typical useBehavior when nested
pxNothing (absolute)NoBorders, shadow offsets, hairlinesAlways the same size
remRoot <html> font sizeYesFont size, spacing, breakpointsAlways the same size
emCurrent element’s font sizeYesLocal values tied to a componentCompounds, can drift

The two columns that decide most arguments are “scales with user font size” and “behavior when nested.” rem wins on both: it respects the reader’s preference and stays predictable. em shares the first benefit but trades away the second.

How each unit is calculated

The math is plain arithmetic. What trips people up is which number you divide or multiply by.

rem uses the root font size:

rem = px ÷ root-font-size

At the default 16px root, 24px ÷ 16 = 1.5rem. To go back, multiply: 1.5rem × 16 = 24px. Every rem on the page uses that same 16 (or whatever you set the root to), which is exactly why rem is predictable.

em uses the current element’s own font size:

em = px ÷ current-element-font-size

If an element’s font-size is 20px, then 1em on that element is 20px, 0.5em is 10px, and a 1.5em padding is 30px. Change the element’s font size and every em value attached to it changes with it. That local coupling is the point of em, and also its trap.

The em compounding trap

Here is the part most guides skip over. When you nest elements that all use em for font size, the values multiply down the tree. Each level inherits the computed font size of its parent and applies its own em factor on top.

.menu      { font-size: 1.2em; } /* parent is 16px → 19.2px */
.menu .item { font-size: 1.2em; } /* parent is 19.2px → 23.04px */
.menu .item .sub { font-size: 1.2em; } /* parent is 23.04px → 27.648px */

Each level is “120% of its parent,” which sounds harmless. But because the parent already grew, the third level is 1.2 × 1.2 × 1.2 = 1.728em relative to the original 16px, about 27.6px, not the 19.2px you might have read off the rule in isolation. Nest a list inside a list inside a component and the text balloons in a way that is hard to trace.

rem sidesteps this entirely. 1.2rem is 19.2px whether it sits at the top of the document or twelve levels deep, because it always measures against the root, never the parent. When a value resolves to a size you did not expect, the first question to ask is whether it is em (parent-relative, compounds) or rem (root-relative, stable). If you are debugging a stray rem and want to see its pixel size fast, the rem to px converter resolves it instantly.

When to use rem

Reach for rem by default. It is the right unit for font sizes, padding, margins, gaps, border-radius, and media-query breakpoints: anything that should scale when a reader adjusts their text size.

That last clause is the accessibility argument, and it is not hypothetical. WebAIM’s Low Vision User Survey has repeatedly found that most respondents change their browser or operating-system default font size, and a meaningful share set it well above the standard 16px. A layout sized in rem honors that change: bump the default to 20px and every rem-based value grows proportionally. A layout sized in px ignores it completely. The text stays locked at its hardcoded size, no matter how much the reader needs it larger.

:root {
  font-size: 16px; /* 1rem = 16px */
}

h1   { font-size: 2rem;     } /* 32px, scales with user preference */
p    { font-size: 1rem;     } /* 16px */
.card { padding: 1.5rem;    } /* 24px */
.card { border-radius: 0.5rem; } /* 8px */

Because every value here is anchored to the same root, a single change to the root font size rescales the whole interface in proportion. That is also what keeps a design system coherent: spacing and type move together instead of drifting apart.

The 62.5% trick

There is a popular shortcut for making rem arithmetic trivial. Set the root font size to 62.5%, which is 62.5% × 16px = 10px:

html {
  font-size: 62.5%; /* now 1rem = 10px */
}

body {
  font-size: 1.6rem; /* restore readable 16px body text */
}

h1 { font-size: 2.4rem; } /* 24px */
p  { font-size: 1.6rem; } /* 16px */

With a 10px root, the mental math collapses to “divide the pixel value by 10”: 24px → 2.4rem, 12px → 1.2rem. The one wrinkle is restoring a readable body size with body { font-size: 1.6rem }, since a raw 10px base leaves default text far too small. Using 62.5% as a percentage rather than 10px keeps it relative, so a reader who scales their browser default still gets proportional growth. If you adopt this base, set the converter’s root font size to 10 so it matches your stylesheet.

When to use em

Use em when you want a value to scale with the element’s own font size, not the root. The classic case is a button:

.btn {
  font-size: 1rem;      /* sized against the root */
  padding: 0.75em 1.5em; /* padding tracks the button's text */
}

.btn--large {
  font-size: 1.25rem;   /* one change resizes everything */
}

Because the padding is in em, the .btn--large modifier resizes the text and its padding together from a single declaration, so the button stays proportional at any size. The same logic applies to an icon sized in em so it matches the line of text it sits in, or letter-spacing that should grow with the font.

A practical strategy is rem for the global skeleton, em for local proportions. Set font size in rem so it answers to the root and the user’s preference; set the handful of values that should track that element in em. Just keep em off anything that nests deeply, or the compounding trap from earlier creeps back in.

When to use px

Some values genuinely should not scale, and px is correct for them: a 1px hairline border, a precise box-shadow offset, a 2px focus ring. These are rendering details, not content. A border that “scales” to 1.25px when the user enlarges their text gains nothing and can render as a fuzzy line. px keeps it crisp.

.divider { border-bottom: 1px solid; }     /* should stay 1px */
.card    { box-shadow: 0 2px 4px rgba(0,0,0,0.1); } /* fixed offset */
.input:focus { outline: 2px solid; }       /* crisp focus ring */

When px is the more accessible choice

This is the part that “always use rem” advice tends to skip. The accessible choice is not “rem everywhere,” it is “scale what should scale, fix what should not.”

A 1px border is a fixed detail. Forcing it into rem so it grows when the user enlarges text does not help readability; it just makes a hairline blurry. For these properties, px is the more accessible choice precisely because it stays put.

The mistake people actually make is the reverse: using px for the things that should respond, like font sizes and breakpoints. That is where px hurts accessibility. So the rule is not about the unit, it is about the property. Ask whether the value is content the reader interacts with (scale it, use rem) or a fixed rendering detail (pin it, use px). The unit follows from the answer.

The media-query trap

This one breaks real layouts and few guides warn about it. Media-query breakpoints written in px do not respond to the browser’s font-size zoom the way you would hope.

Picture a breakpoint at width: 600px where a sidebar collapses. A user with reduced vision sets their browser default to 24px to read comfortably. Your content now needs more horizontal room, since the larger text wants to reflow sooner. But a px breakpoint does not know the text grew; it still flips at exactly 600px of viewport, so the layout switches at the wrong moment and content gets cramped or overlaps.

The two approaches differ:

/* px breakpoint — ignores the user's font-size preference */
@media (min-width: 600px) {
  .sidebar { display: block; }
}

/* em/rem breakpoint — responds to the user's font size */
@media (min-width: 37.5em) {
  .sidebar { display: block; }
}

37.5em is 600px at the default 16px (600 ÷ 16 = 37.5). The difference is behavioral: when the user doubles their default font size, the em breakpoint effectively doubles too, so the layout switches at a viewport width proportional to the text, exactly when the content needs it. The px breakpoint stays frozen.

One quirk worth knowing: in media-query conditions, em and rem both resolve against the browser default font size, not any html override, so they behave identically there. Either unit fixes the bug; px causes it.

The per-property decision table

When you are unsure, this table answers it without re-deriving the logic each time.

PropertyRecommended unitWhy
font-sizeremScales with the user’s font-size preference
padding / marginremSpacing scales together with text
borderpxHairlines should stay crisp and fixed
box-shadow offsetpxA precise rendering detail, not content
border-radiusremKeeps corner roundness proportional to scale
media queryem / remBreakpoints must respond to font-size zoom
width / max-widthrem (often ch for text)Scalable layout widths; ch caps line length
line-heightunitlessA unitless multiplier inherits correctly

The line-height row deserves a note because it is a common bug. Always write line-height: 1.5, with no unit. A unitless value is a multiplier each element computes against its own font size, so nested elements stay legible. Write line-height: 1.5em or 24px instead and the computed length is inherited, which means a child with a larger font size keeps the parent’s line height and its text starts to collide. Unitless avoids that problem.

Converting between px and rem

The arithmetic is small enough to do in your head once you hold the anchor: 16px = 1rem. Divide by 16 to go to rem, multiply by 16 to go back to px.

pxrem (16px base)
8px0.5rem
12px0.75rem
16px1rem
24px1.5rem
32px2rem

If you use the 62.5% trick, the base becomes 10px and the math is even simpler: just divide or multiply by 10, so 24px = 2.4rem. The only rule is to always convert against the base your stylesheet actually sets.

For everything else, like odd values, a custom root, or batch-converting a Figma export, skip the mental math and use the px to rem converter or the rem to px converter. Both let you set any root font size and convert in either direction in real time. And if you are tidying up a stylesheet full of mixed units afterward, the CSS formatter will normalize the spacing and indentation for you.

Common mistakes

A few patterns cause most unit-related grief.

Setting the root font size in px is the first. Writing html { font-size: 16px } (rather than leaving the default or using 100% / a percentage) overrides the user’s browser font-size preference outright. Rem values still compute against it, but the reader can no longer scale the whole page. Leave the root as the default, or use a percentage.

Mixing px and rem with no system is the second. Some font sizes in px, some in rem, spacing split between both, and the result is a layout that scales unevenly when a user adjusts their text. Pick rem as the default and reserve px for the deliberate exceptions in the decision table.

Using em for global spacing reintroduces the compounding trap, so a padding deep in the tree resolves to something nobody intended. Keep global spacing in rem and save em for local, component-scoped values.

Giving line-height a unit is the last. As covered above, line-height: 24px or 1.5em gets inherited as a computed length and breaks on elements with different font sizes. Always use a unitless multiplier.

FAQ

Is rem better than px?

For most sizing, yes: rem is better than px because it scales with the user’s browser font-size preference, which px ignores. But “better” depends on the property. px is the right choice for fixed details like 1px borders and shadow offsets that should stay crisp. Use rem for content sizing, px for rendering details.

What is 1rem in pixels?

1rem equals the root font size in pixels, which is 16px by default in virtually all browsers. So 1rem = 16px, 1.5rem = 24px, and 2rem = 32px on a standard setup. If a stylesheet overrides html { font-size }, for example to 10px via the 62.5% trick, then 1rem equals that value instead.

Should I use rem or em for font-size?

Use rem for font-size in almost every case. Rem measures against the root, so it stays predictable no matter how deeply an element is nested. Em measures against the parent’s font size, which compounds down the tree and makes nested text balloon unexpectedly. Reserve em for local values tied to a single component.

When should I use px instead of rem?

Use px for values that should not scale with the user’s font size: 1px borders, precise box-shadow offsets, focus-ring outlines, and other fixed rendering details. These are crisp design details rather than content, so pinning them in px is the more accessible choice. Everything content-related should still use rem.

Why do media queries break when I use px?

Media-query breakpoints in px do not respond to the browser’s font-size zoom. When a user enlarges their default font, their content needs more room, but a px breakpoint still flips at the same viewport width, so the layout switches at the wrong moment. Use em or rem breakpoints, which scale with the user’s font size.

What is the 62.5% font-size trick?

The 62.5% trick sets html { font-size: 62.5% }, making the root font size 10px (62.5% of 16). With a 10px base, rem math becomes “divide by 10”: 24px = 2.4rem, 12px = 1.2rem. Developers then set body { font-size: 1.6rem } to restore readable 16px body text.

Is it OK to mix px, rem, and em?

Yes, mixing px, rem, and em is correct when each follows the property it suits: rem for type and spacing, px for fixed details, em for local component-scoped values. What causes trouble is mixing them with no system, like some font sizes in px and some in rem. Choose rem as the default and treat px and em as deliberate exceptions.

What unit should I use for padding and margin?

Use rem for padding and margin so spacing scales together with text when the user adjusts their font size. This keeps a layout proportional and accessible. Reserve em for padding that should track an element’s own font size, like a button whose padding grows with its text, and avoid em on deeply nested containers where it compounds.

Tags: css rem em frontend accessibility responsive-design

Related Articles

View all articles