ForgeFrontend — Prepare, Practice, Crack
Secure checkout
Lifetime access
Instant PDF download
Free updates forever

Prepare · Practice · Crack

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.

emrem
Relative toThe element's own font sizeThe root (`html`) font size
Default valueInherited — usually 16px16px, unless `html` changes it
Compounds when nestedYesNo
Predictable in a componentNo — depends on where it landsYes — same everywhere
Respects browser font settingsYesYes
Best forPadding, margins, spacing tied to textFont sizes, layout, media queries
Stands forThe width of an “M” in metal typeRoot em
One question separates them: relative to what?

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.

The same declaration, two different resultscss
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.

The classic nested-list blowoutcss
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.

One button, three sizes, one rulecss
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.

The rem-outside, em-inside patterncss
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 → ₹499

The 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.

How the user's preference flows throughcss
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.

Breakpoints that respond to the user's font sizecss
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.

PropertyUseWhy
font-sizeremPredictable, respects the user's setting
padding / margin inside a componentemScales with the component's own text
margin between layout sectionsremShould not depend on nearby font sizes
width / max-width of text blocksch or remLine length is a typographic measure
border-widthpxA hairline should stay a hairline
media query breakpointsem or remShifts with the user's font preference
line-heightunitlessInherits as a ratio, not a computed length
A practical unit-by-property guide.

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.

Conversions worth memorisingcss
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.

A spacing scale you only define oncecss
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
Written by Arun Karthikeyan · Last updated

Full kit

Complete Frontend Kit · ₹499

Get it →