em vs rem in CSS
Short answer
Both are relative length units. 1rem is always the root font size — 16px by default — no matter where it appears. 1em is the font size of the element it is used on, which is usually inherited from the parent, so nested ems compound. Use rem for predictable sizing, em for spacing that should scale with its own text.
| em | rem | |
|---|---|---|
| Relative to | The element's own font size | The root (`html`) font size |
| Default value | Inherited — usually 16px | 16px, unless `html` changes it |
| Compounds when nested | Yes | No |
| Predictable in a component | No — depends on where it lands | Yes — same everywhere |
| Respects browser font settings | Yes | Yes |
| Best for | Padding, margins, spacing tied to text | Font sizes, layout, media queries |
| Stands for | The width of an “M” in metal type | Root em |
What each unit is actually measuring
Both units are multipliers on a font size — the only question is whose. rem multiplies the font size of the root element, which is the `html` tag. That value is 16px in every major browser unless the user has changed it or your CSS overrides it, and it is the same number no matter how deeply nested the element using it is.
em multiplies the font size of the element the unit appears on. When you set `font-size: 1.5em`, the base is the inherited font size from the parent, because the element does not have its own font size yet. When you set `padding: 1.5em` on an element that also has its own font size, the base is that element's font size, not the parent's. That distinction trips up almost everyone the first time.
1html { font-size: 16px; } /* the rem base */
2
3.card {
4 font-size: 20px;
5 padding: 1em; /* → 20px — this element's own font size */
6 margin-bottom: 1rem; /* → 16px — the root font size */
7}
8
9.card p {
10 font-size: 1em; /* → 20px — inherited from .card */
11 margin-top: 1rem; /* → 16px — still the root */
12}Compounding: the reason rem exists
Because em is relative to the inherited font size, nesting multiplies. Two levels of `1.2em` is not 1.2 times the base — it is 1.44 times. Four levels is 2.07 times. In a component tree you do not fully control, this is how a nav item ends up rendering at 26px when the design says 16px, and why the bug is so hard to trace: every individual rule looks correct.
1html { font-size: 16px; }
2ul { font-size: 1.2em; }
3
4/* Rendered result:
5 <ul> → 19.2px
6 <ul> → 23.04px
7 <ul> → 27.65px
8 <ul> → 33.18px ← nobody designed this
9*/
10
11/* With rem, nesting changes nothing: */
12ul { font-size: 1.2rem; }
13/* every level → 19.2px */The mirror image is just as common and even more confusing: an em value that shrinks. Set `font-size: 0.9em` on a wrapper and again on something inside it, and the inner text lands at 0.81 of the base. Applied down a deep tree, text quietly becomes unreadable without any single rule looking wrong.
When em is the better choice
em gets an unfair reputation from the compounding problem, but there is one job it does that rem cannot: keeping a component's internal proportions intact when its font size changes. If a button's padding is in em, making the button's text larger enlarges the padding by the same ratio, and the button keeps its shape. In rem, the text grows and the padding stays put, so the button looks cramped.
1.btn {
2 font-size: 1rem; /* set the scale from the root */
3 padding: 0.75em 1.5em;/* proportional to THIS button's text */
4 border-radius: 0.375em;
5}
6
7.btn--sm { font-size: 0.875rem; } /* padding → 10.5px 21px */
8.btn--lg { font-size: 1.25rem; } /* padding → 15px 30px */
9
10/* If padding were in rem it would stay 12px/24px at every size,
11 and the large button would look under-padded. */The pattern generalises: set the font size in rem, then express everything inside the component in em. You get the predictability of a root-relative scale at the component boundary and the proportionality of em inside it. This is what most well-built design systems do, and being able to state that rule is a strong answer.
1.badge {
2 font-size: 0.75rem; /* → 12px, fixed against the root scale */
3 padding: 0.25em 0.6em; /* → 3px 7.2px, proportional to the badge's text */
4 gap: 0.4em; /* → 4.8px */
5 line-height: 1.4; /* unitless: the one exception, see below */
6}
7
8/* Drop .badge inside a heading, a table cell or a card —
9 it renders identically in all three. */This is 1 of 200+ questions in the Complete Frontend Kit
Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.
⚡ Get the Complete Frontend Kit → ₹499The accessibility argument against px
The strongest practical reason to use either unit over px is that both respond to the browser's font-size setting and px does not. A user who has set their default text size to 20px because they find 16px hard to read gets larger text everywhere you used rem or em, and no change at all where you used px. Roughly one in twenty users has changed that setting.
Note that this is separate from zoom. Browser zoom scales px, rem and em alike, so px does not break zooming. What px breaks is the font-size preference specifically — and that is the setting people with low vision actually use, because zoom enlarges the whole layout including images and chrome.
1/* User sets browser default to 20px instead of 16px */
2
3.title { font-size: 24px; } /* → 24px — unchanged, ignores the user */
4.title { font-size: 1.5rem; } /* → 30px — scales with the preference */
5.title { font-size: 1.5em; } /* → 30px — also scales, if nothing overrides */
6
7/* Which is why this is the one line to avoid: */
8html { font-size: 16px; } /* pins the root and cancels the preference */
9
10/* Prefer leaving the root alone, or: */
11html { font-size: 100%; } /* explicit, and still respects the user */Media queries always use the root
There is one place where em and rem behave identically, and it surprises people: inside a media query, em is evaluated against the initial root font size, not against any element. There is no element yet when a media query is resolved, so both units mean the same thing. The practical consequence is that changing `html { font-size }` does not shift your breakpoints.
1/* These two are equivalent — both resolve against the initial 16px */
2@media (min-width: 48em) { /* → fires at 768px */ }
3@media (min-width: 48rem) { /* → fires at 768px */ }
4
5/* And unlike px, they shift when the user enlarges their default text:
6 at a 20px browser default, 48em → 960px, so a phone-sized layout
7 is kept for longer — which is usually what that user wants. */
8
9@media (min-width: 768px) { /* fixed forever, ignores the preference */ }Using em or rem breakpoints is a small, cheap accessibility win that almost no site bothers with. Mentioning it in an interview signals that you have thought about responsive design beyond copying the Bootstrap breakpoint list.
Where neither belongs
Relative units are not universally correct. Some properties are measuring physical rendering rather than text, and tying them to a font size produces odd results. Border widths are the clearest case: a 1px hairline should stay a hairline. Same for anything that must align to the device pixel grid.
| Property | Use | Why |
|---|---|---|
| font-size | rem | Predictable, respects the user's setting |
| padding / margin inside a component | em | Scales with the component's own text |
| margin between layout sections | rem | Should not depend on nearby font sizes |
| width / max-width of text blocks | ch or rem | Line length is a typographic measure |
| border-width | px | A hairline should stay a hairline |
| media query breakpoints | em or rem | Shifts with the user's font preference |
| line-height | unitless | Inherits as a ratio, not a computed length |
How to convert between them
The arithmetic is simple once you know which base applies. For rem, divide the pixel value you want by the root font size. For em, divide by the computed font size of the element in question — which means you have to know it, and that is precisely why em is harder to reason about in a large codebase.
1/* Root at the default 16px — px / 16 gives you the rem value
2 12px → 0.75rem
3 14px → 0.875rem
4 16px → 1rem
5 18px → 1.125rem
6 24px → 1.5rem
7 32px → 2rem */
8
9/* px → em : divide by THIS element's computed font-size */
10.card {
11 font-size: 20px;
12 padding: 0.5em; /* → 10px */
13 gap: 1.5em; /* → 30px */
14}
15
16/* Or let the browser do the arithmetic — mixing units is fine */
17.card__inner { padding: calc(1rem + 0.5em); } /* → 16px + 10px = 26px */If you would rather not divide by 16 all day, keep a scale as custom properties and use the names instead of the numbers. It also gives you one place to adjust the whole system, which is worth more than the arithmetic saved.
1:root {
2 --space-1: 0.25rem; /* → 4px */
3 --space-2: 0.5rem; /* → 8px */
4 --space-3: 0.75rem; /* → 12px */
5 --space-4: 1rem; /* → 16px */
6 --space-6: 1.5rem; /* → 24px */
7 --space-8: 2rem; /* → 32px */
8}
9
10.card { padding: var(--space-4); gap: var(--space-2); }What about the newer units — ch, ex, cap, lh?
They are all font-relative like em, just measuring different parts of the font. ch is the width of the "0" glyph and is genuinely useful for line length: max-width: 65ch gives a comfortable reading measure that adapts to the actual typeface. lh equals the element's line-height and is handy for vertical rhythm. ex and cap are rare outside typography work.
Should I use rem or vw for responsive font sizes?
Neither alone. Pure vw ignores the user's font-size preference entirely and gets uncomfortably small on narrow screens. The usual answer is clamp() with a rem floor and ceiling: font-size: clamp(1.5rem, 4vw, 3rem) scales fluidly but never below or above sizes you chose.
Does rem work inside shadow DOM or an iframe?
Inside shadow DOM, rem still resolves against the outer document's root — the shadow boundary does not create a new root. An iframe is a separate document with its own html element, so rem there resolves against that document's root font size instead.
Is there a performance difference?
Nothing measurable. Both are resolved during style computation, and the extra multiplication for a nested em is trivial next to layout and paint. Choose based on maintainability, never on speed.
What does rem actually stand for?
Root em. And em is named after the letter M, which in metal typesetting occupied a square block the same width as the type's point size — the origin of "em dash" and "em space" too. The unit has always meant "one font size wide".
Frequently asked questions
- What is the difference between em and rem in CSS?
- rem is relative to the root element's font size, which is 16px by default and the same everywhere on the page. em is relative to the font size of the element it is written on, which is normally inherited from the parent — so ems compound when elements nest and rems never do.
- What is rem in CSS?
- rem stands for "root em". It is a length unit equal to the computed font size of the html element, so 1rem is 16px on a default browser setup. Because the base is fixed at the root, a rem value means the same thing anywhere in the document.
- Should I use em or rem for font size?
- rem, in almost every case. Font sizes set in rem are predictable regardless of where the element sits in the tree, which is what you need in a component that can be dropped anywhere. Reserve em for font sizes when you deliberately want text to scale with its container's text.
- Why does my text get bigger with each nested element?
- You have set a font size above 1em on an element that nests inside itself — a list inside a list, or a container class applied twice. Each level multiplies the previous one, so 1.2em three deep renders at 1.73 times the base. Switching that rule to rem fixes it immediately.
- Is rem better than px for accessibility?
- Yes, for text. Browsers let users raise the default font size, and rem and em respond to that setting while px ignores it. Zoom scales all three, so px does not break zooming — but it does override the preference of the users most likely to need it.
- What does 1rem equal in pixels?
- 16px on a default browser configuration, because that is the default font size of the html element. If your CSS sets html { font-size } to something else, or the user has changed their browser's default text size, 1rem equals that value instead.
- Should I use em or rem for padding and margin?
- Use em for padding inside a component so the spacing scales with that component's own text — a large button then keeps its proportions. Use rem for margins between layout sections, where the gap should not depend on whatever font size happens to be nearby.
- Do em and rem work in media queries?
- Yes, and inside a media query they behave identically: both resolve against the initial root font size, since there is no element to inherit from. em breakpoints are a good idea because they shift when a user enlarges their default text, keeping a simpler layout for longer.
- Is html { font-size: 62.5% } a good idea?
- It makes 1rem equal 10px, which simplifies the arithmetic, but it also shrinks the user's chosen base size by 37.5%. If you use it, set a compensating body { font-size: 1.6rem } so normal text returns to the intended size and only the maths shortcut remains.
- What is the difference between em and rem in Tailwind CSS?
- Tailwind's default spacing and type scales are expressed in rem — text-base is 1rem, p-4 is 1rem — so the framework already follows the rem-for-sizing convention. You reach for em only in custom CSS or arbitrary values where you want something to scale with local text.
- Can I mix em, rem and px in the same stylesheet?
- Yes, and well-built stylesheets do. A common split is rem for font sizes and layout rhythm, em for component-internal spacing, px for hairline borders and anything that must land on the device pixel grid. calc() lets you combine them in a single value where needed.
- Why is my line-height wrong on nested elements?
- Because you gave it a unit. line-height: 1.5em computes to a fixed pixel value on the parent and children inherit that number, so larger text inside gets lines that are too tight. Use the unitless line-height: 1.5 so each element recalculates the ratio against its own font size.
This is 1 of 200+ questions in the Complete Frontend Kit
Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.
⚡ Get the Complete Frontend Kit → ₹499