px vs rem vs em: what each unit is relative to, and which to use where
Three units, one argument: should a button's padding be 12px, 0.75rem or 0.75em? The answer depends on what should happen when the user enlarges their browser's default text โ which many people do โ and on what each unit is measured against. The px to rem converter does the arithmetic; this guide settles the choice.
What a pixel is (it isn't a pixel)
A CSS pixel is not a hardware pixel. It is defined as 1/96 of an inch at arm's length โ a reference size โ and the browser maps it to device pixels using the device's pixel ratio: 1 CSS px is 2ร2 device pixels on a 2ร "retina" screen, 3ร3 on many phones. So 16px text is the same physical size on any device regardless of resolution, and that consistency is why px remains useful for things that shouldn't scale with text: borders, shadows, hairlines, image dimensions. What px does not do is respond to the user's font-size preference in browser settings, which is where the argument starts.
rem: relative to the root
1rem equals the font size of the root element (html), which by default is the browser's setting โ 16px unless the user has changed it. 1.5rem is 24px at default and 30px for a user who set 20px. Everything sized in rem scales together with that preference: text, spacing, container widths, breakpoints. That is the accessibility argument for rem, and it is why 16px = 1rem is the conversion everyone remembers (and why 0.875rem is 14px, 1.125rem 18px, 0.5rem 8px). A common trick โ setting html { font-size: 62.5% } so 1rem is 10px โ makes the maths easier and still respects the user's setting proportionally.
em: relative to the parent, and why it compounds
1em equals the font size of the element itself (for font-size, its parent's). Nest three elements each at 1.2em and the innermost text is 1.2ยณ = 1.73 times the base โ compounding that surprises everyone once. That same behaviour is a feature inside a component: padding of 0.75em on a button scales with the button's own font size, so a small button and a large button keep their proportions without extra rules. em is for spacing that belongs to the text it surrounds โ padding, letter-spacing, icon sizes beside text โ and for media queries in older code.
Which unit where
- Font sizes: rem. Never px, which ignores the user's preference.
- Layout spacing, margins, max-widths, grid gaps: rem, so the whole layout scales with text.
- Padding and spacing inside a component: em, to scale with that component's text.
- Borders, outlines, shadows, hairlines: px. A 1px border should stay 1px.
- Media queries: em or rem (they respond to zoom and font settings consistently across browsers); px is common and slightly worse.
- Images and icons: px or rem depending on whether they should grow with text; SVG icons beside text in em.
Viewport, percentage and the rest
vw and vh are percentages of the viewport width and height โ for full-bleed sections and fluid type (with clamp() to keep it sane), with the caveat that 100vh misbehaves on mobile browsers whose toolbars come and go (dvh fixes it). Percentages are relative to the parent's corresponding dimension โ fine for widths, confusing for heights. ch is the width of a "0", handy for line lengths (65ch is a readable paragraph). Absolute units (in, cm, pt) are for print stylesheets only. The box shadow generator and gradient generator output px because that's what those properties want; the flexbox playground shows how the units interact in a layout, and Flexbox vs Grid: which one, when covers the layout side.
Sources and further reading
The claims in this guide rest on these references, which were checked when the guide was last updated. Spotted an error? The contact page says how to report it.