BrowserTools
webdev

PX vs REM vs EM: Which Unit Belongs Where

px ignores the font size a reader has set, rem follows the root element, and em follows the parent, so nesting em compounds while rem never surprises you. That single difference is the whole accessibility case for font-size guidance, and it is what decides where each unit belongs in a layout. The rule of thumb, the arithmetic and the traps are below; to convert one specific value, the PX to REM converter linked from this guide does it instantly.

By Guga — BrowserTools maintainer, Tbilisi, Georgia·Last updated 2026-10-01·4 min read·869 words

Free and instant. Set your own root font size and it converts both directions, with the CSS snippet and a Tailwind size reference beside it.

convert pixels to rem, or rem back to pixels, in your browser →

What px, rem, and em actually mean

PX is a CSS pixel, not a device pixel. On a 2x Retina display, 1 CSS px maps to 4 device pixels, but to the layout it is still one unit. PX is absolute with respect to the root: 16px is always 16px regardless of parent. EM is relative to the computed font-size of the element's parent. If a card has font-size 20px, then 1.5em inside equals 30px. Nesting em compounds, which surprises beginners: 0.9em inside 0.9em becomes 0.81 of the root. REM stands for root em and is always relative to html font-size. If html is 16px, then 2rem is 32px everywhere. This single reference makes rem predictable for design systems while em remains useful for component encapsulation.

Conversion math with code examples

The base is root font-size, default 16px in every browser. Generic: rem = px / root. So 12px with root 16 is 0.75rem, 14px is 0.875rem, 18px is 1.125rem, 40px is 2.5rem. Common scale with Tailwind-like steps: 4px 0.25rem, 8px 0.5rem, 16px 1rem, 24px 1.5rem, 32px 2rem, 48px 3rem. In JavaScript: const toRem = (px) => `${px/16}rem`; In SCSS helper: @function rem($px){ @return $px/16 * 1rem; } Example responsive card: .card{ padding: 1.5rem; font-size: 1rem; } .card h2{ font-size: 1.25rem; margin-bottom: 0.5em; } Note the h2 margin uses em so it scales with h2 size, while card padding uses rem to stay aligned to page rhythm. For media queries, rem also respects user zoom better than px in modern browsers.

When to use each unit: practical rules

Use rem for: font sizes, section padding, gaps, container widths, and any spacing that defines reading rhythm. This ensures a user who prefers 18px base gets proportionally larger UI without horizontal scroll at 400% zoom. Use em for: intra-component scaling where the parent controls density. Example: .btn{ font-size: 0.875rem; padding: 0.6em 1.2em; } If you later set .btn--large{ font-size: 1.125rem; } padding automatically enlarges. Use px for: 1px borders, box-shadows, pixel-perfect pixel art, and canvas-aligned work where scaling would blur. Use ch or ex for line length: max-width 65ch gives 45-75 characters per line, the readability sweet spot. Avoid setting html font-size to 10px or 62.5% to simplify math; it forces users with 20px preference to recalc and breaks third-party embeds that assume 16px.

Accessibility, browser zoom, and user preferences

WCAG 1.4.4 requires text to be resizable up to 200% without loss of content. Both px and rem zoom when the user hits Ctrl+, but rem also responds to the browser's default font size setting under Settings → Appearance. Testing with 24px default: a rem-based layout grows everywhere, while a px-based layout stays at 16px text with larger chrome only, failing user expectation. Chrome DevTools → Rendering → Emulate prefers and set font size to verify. For line height, use unitless values like 1.6 rather than 1.6rem; unitless multiplies by element font-size, whereas 1.6rem anchors to root and breaks tight heading rhythm. Always test at 320px width and 400% zoom to catch fixed-width px containers that overflow.

A workflow that prevents confusion

Design in Figma in px, but export spacing as rem. Keep a table: spacing-xs 4px 0.25rem, spacing-sm 8px 0.5rem, spacing-md 16px 1rem, spacing-lg 24px 1.5rem, spacing-xl 32px 2rem. In code, store tokens as rem: --space-4: 1rem; Apply clamp for fluid type: font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem); This blends rem base with viewport growth without media query jumps. For legacy sites mixing px and rem, search with regex for :\s*(\d+)px and convert incrementally, starting with typography then spacing. BrowserTools PX to REM converter lets you enter 16, 18, 24, 32 and copies the rem string plus the reverse check. Paste once and you avoid rounding errors like 0.9375rem vs 0.94rem that compound in grids.

Common mistakes and how to fix them

Mistake one: nesting em for margins, causing exponential growth. Fix by using rem for margins between components and reserving em for inside a component. Mistake two: setting html 62.5% to make 10px base; this harms accessibility and math is trivial anyway with calc or a tool. Mistake three: using rem inside SVG that expects px viewBox units; keep SVG attributes in px and scale container with rem. Mistake four: forgetting to set line-height after switching to rem; pair with line-height 1.5 for body text. Example fix: before .title{ font-size: 24px; margin: 16px 0; } after .title{ font-size: 1.5rem; margin: 1rem 0; line-height: 1.2; } The visual match is identical at default settings but now respects a 20px user preference, lifting 24px to 30px automatically.

Frequently Asked Questions

What is 16px in rem?
With the default root font-size of 16px, 1rem equals 16px. So 16px equals 1rem, 24px equals 1.5rem, and 32px equals 2rem. If you change html { font-size: 62.5% } to make 1rem = 10px, then 16px becomes 1.6rem, but that breaks user font scaling and is not recommended.
Should I use rem for everything?
Use rem for font sizes, spacing, and layout that should scale with the user's preferred font size. Use px for borders and hairlines where you want a fixed 1px regardless of zoom. Use em for component-local scaling such as button padding that should grow with the button's own font size.
Does using rem improve accessibility?
Yes. Users who set a default font size of 20px in browser settings expect 1rem to equal 20px. If you size text in px, you override that preference. Text sized in rem respects the setting and still zooms correctly, passing WCAG 1.4.4 Resize Text.
What is the formula to convert px to rem?
rem = px / rootFontSize. With root 16px, 18px becomes 1.125rem. In code: function pxToRem(px, root=16){ return px/root + 'rem'; }. Our PX to REM tool does this instantly and shows the reverse.