What Is the Difference Between px, rem, and em in CSS?
px, rem, and em all set sizes in CSS, but they behave very differently once your styles start nesting. If you want a fast way to sanity-check values while you work, try our free font size converter and skip the napkin math.
The short version: px is the most direct and predictable, rem scales from the root font size, and em scales from the current element’s context. Pick the wrong one, and a neat component system turns into a chain reaction of weird spacing and oversized buttons.
What each unit actually means
px means CSS pixels. It is the simplest unit to read because 16px always means the same CSS value in your stylesheet, even though the physical display behind it may map that differently depending on device density.
rem means root em. It is relative to the root element, usually html, so if the browser default is 16px, then 1rem equals 16px, 1.5rem equals 24px, and 2rem equals 32px.
em is relative to the font size of the current element, or the inherited size already in play there. That makes it powerful for local scaling, but also easy to compound when nested components inherit from one another.
html { font-size: 16px; }
.card { font-size: 1rem; }
.card h2 { font-size: 1.5rem; }
.card p { font-size: 1em; }In that example, rem stays anchored to the page root while em tracks the element’s own context. The same word-sized tweak can behave very differently depending on which one you picked.
px is for precision, rem is for system-wide scale
Use px when the design really needs a fixed visual result. Hairline borders, icon offsets, and pixel-tight adjustments often land here because you want them to stay exactly where you put them.
Use rem when you want the whole interface to respond together. That is why many teams set font sizes, spacing, and layout gaps in rem: if the root font size changes, the whole system scales without you hunting through every component.
This also plays nicely with accessibility. If a user bumps their base font size or the browser default changes, rem-based typography grows with it instead of ignoring the setting.
A common pattern looks like this:
:root {
font-size: 16px;
}
body {
font-size: 1rem;
}
h1 {
font-size: 2.5rem;
}
button {
padding: 0.75rem 1rem;
}That gives you a predictable scale without hardcoding every value in pixels. It also makes design tokens easier to reason about, because a spacing unit can mean the same thing across the app.
em is local, which is both useful and dangerous
em shines when you want a component to scale based on its own text size. Padding inside a button is the classic case: if the button text gets larger, the padding can grow with it and preserve balance.
That same behavior can get messy when elements inherit from other elements that already use em. Two levels deep, a value can be larger than you intended because it is multiplied by the parent’s size and then multiplied again.
.menu {
font-size: 1.25rem;
}
.menu-item {
font-size: 1em;
padding: 0.75em 1em;
}
.menu-item .badge {
font-size: 0.8em;
}Here, .badge is not just 80% of the base page font. It is 80% of the menu item’s current context, which may already be larger than the root. That is fine when you want a nested scale, but annoying when you expected a single global baseline.
If you want a deeper mental model for nested styles, our guide on the difference between px, rem, and em in CSS pairs well with this one. The main thing to remember is that em is contextual by design.
When to choose each unit in real projects
If you are building a design system, rem should probably be your default for typography, spacing, and layout scales. It gives you one root control knob and keeps component math consistent across the app.
If you are styling something that should scale with its own text, em is a good fit. Buttons, chips, badges, and form controls often benefit from local scaling because the text and padding stay proportionate.
If you need exact visual control, px still has a place. Borders, shadows, and tiny alignment nudges are usually easier to manage when the value does not drift with font size changes.
- Typography scale: usually
rem - Component-local spacing: often
em - Pixel-perfect detail work:
px
One practical rule: if changing the user’s base text size should affect it, lean toward rem or em. If the size should stay visually locked, use px.
Why nesting changes everything
The reason developers get burned by px rem em is not the units themselves. It is inheritance. CSS does what you told it to do, not what you meant in the issue ticket.
Consider a card component with nested text and spacing. If the card sets font-size: 1.125rem, then any child using em inherits that larger baseline before applying its own multiplier. That can be perfect for compact UI, or it can be why a dropdown suddenly looks inflated.
rem avoids that problem because it always references the root. That makes it easier to predict in deep component trees, especially when you are using utility classes, theming, or third-party UI libraries.
em is still useful for self-contained pieces. It just asks for more discipline. If you mix it casually into nested layouts, the math becomes a layered stack of assumptions.
A Worked Example
Say you want a callout box with text, padding, and a button. You want the box to scale with the page, but you also want the button to feel proportionate inside the box.
:root {
font-size: 16px;
}
.callout {
font-size: 1rem;
padding: 1.5rem;
border: 1px solid #444;
}
.callout h2 {
font-size: 1.5rem;
margin-bottom: 0.75rem;
}
.callout p {
font-size: 1rem;
margin-bottom: 1rem;
}
.callout button {
font-size: 1em;
padding: 0.75em 1em;
}Now do the math. The callout’s padding is 1.5rem, so it is 24px if the root is 16px. The button inherits the callout’s current font size, so 1em inside the button stays equal to the callout text size, and the padding grows with it.
If you swapped the button to padding: 0.75rem 1rem, the padding would ignore the button’s own font size and follow the root instead. That is often cleaner for app-wide consistency, especially when button labels change length or scale.
Here is the basic before/after thinking:
Before:
- padding and text sizes mixed inconsistently
- nested components scale unpredictably
- each tweak needs manual recalculation
After:
- rem for root-based sizing
- em for local component proportions
- px only where you need hard precisionIf you are converting values while refactoring, the tool at the top will save time. It is easier to verify one spacing token than to eyeball whether a nested component just doubled itself.
How browser defaults and accessibility affect the math
Most browsers start with a default root font size around 16px, but users can change that. When they do, rem tracks the new root size automatically, which is one reason it is a safer default for readable text.
px can still be zoomed by the browser, but it does not respond the same way to font-size preferences. That is why an all-px interface can feel rigid compared with a rem-based one.
This is not about dogma. It is about choosing the unit that matches the behavior you want. If the value should respect text scaling, do not lock it down with pixels out of habit.
A useful compromise is this: keep typography and spacing on rem, reserve em for component internals, and use px for borders or tiny details. That gives you a sane baseline without turning every stylesheet into a unit ideology contest.
Frequently Asked Questions
Is rem better than px for font sizes?
Usually, yes, if you care about scalable text and consistent sizing across the site. rem follows the root font size, so it adapts more cleanly when the browser default or user preferences change. px is still fine for exact control, but it is less flexible for type.
Why does em get bigger inside nested elements?
Because em is relative to the current element’s font-size context, and that context is often inherited from the parent. If a parent already uses a larger size, the child’s em value multiplies against that. Nest it a few levels deep and the math compounds fast.
Should I use em for padding and margins?
Sometimes. em is good when spacing should scale with the element’s text, such as a button or badge. If you want spacing to stay aligned to the global design scale, rem is usually easier to maintain.
What is the difference between 1rem and 1em?
1rem always equals the root font size, while 1em equals the current element’s font size. On a page with a 16px root, both may start at 16px, but they diverge as soon as the element inherits or sets a different size. That difference is the whole game.
The Bottom Line
The cleanest way to think about px rem em is simple: px is fixed, rem is global, and em is local. If you keep that model in your head, most CSS sizing choices get a lot less mysterious.
For most modern UI work, start with rem for text and spacing, use em when a component should scale from its own font size, and keep px for the stuff that really needs to stay exact. When the numbers get annoying, use this font size converter tool and move on with your life.
That is usually enough to keep your layout from drifting into compounded nonsense. The browser is already doing enough math behind your back.