In CSS, what is the difference between px, em, and rem, and why can nested em values compound unexpectedly?
answer
- which font-size does it look at
- em on font-size vs em elsewhere
- relative values multiply down the tree
- rem anchors to the html element
- 0.9em nested three deep is 0.73
basics
~20 spx is absolute. em resolves against the element's own computed font-size — or the parent's, when you are setting font-size itself — so nested em font sizes multiply. rem always resolves against the root element's font-size, so it never compounds.
solid answer
~50 s`px` is an absolute CSS unit: `16px` is `16px` everywhere. `em` is relative to a font size, but which one depends on the property. On `font-size`, `1em` means the **parent's** computed font-size; on every other property (`padding`, `width`, `margin`, `gap`, `border-radius`) `1em` means the **element's own** computed font-size. That first case is where compounding comes from: if `.menu li { font-size: 0.9em }` and list items nest three deep, you get 0.9 × 0.9 × 0.9 of the original, so text shrinks the deeper it goes — nobody wrote that, the multiplication did. `rem` sidesteps this by always resolving against the root element's computed font-size (the `html` element), so `1.25rem` is the same length no matter how deep the element sits. Practical rule: `rem` for type and layout rhythm, `em` when you deliberately want a value to scale with the component's own text (button padding, icon size), `px` for things that genuinely should not scale, like hairline borders.
code
css · 11 lineshtml { font-size: 16px; }
.card {
font-size: 1.5em; /* 1.5 x parent (16px) = 24px */
padding: 1em; /* 1 x OWN font-size (24px) = 24px */
border-radius: 1rem; /* 1 x root (16px) = 16px */
}
/* Compounding: each nested level multiplies again */
ul { font-size: 0.9em; }
/* depth 1 = 0.9 | depth 2 = 0.81 | depth 3 = 0.729 */go deeper
Be able to say plainly that px is fixed, rem is relative to the root font-size, and em is relative to a nearby font-size — and that rem is the safe default for type.
Explain the two resolution rules for em: parent's font-size inside font-size, the element's own font-size everywhere else, and walk through a nested 0.9em example to show the multiplication.
Show judgment about where each unit belongs in a real codebase: rem for the type scale, em for component-internal spacing that should track its own text, px for hairlines — and be ready to diagnose depth-dependent text drift from a screenshot.
Own the system-level tradeoff: a unit convention encoded in tokens is what keeps a large stylesheet consistent, and mixing conventions per team is what produces unfixable drift. Be ready to argue why the root font-size is a contract nobody overrides casually.
## The three units `px` is an absolute length in CSS. It is not a physical device pixel — it is a CSS pixel, an anchored reference unit — but for authoring purposes it behaves as a fixed number that does not depend on anything else in the document. `em` and `rem` are *font-relative* lengths. Both resolve to a length by multiplying by some font-size; the whole difference is **which** font-size they look at. ## How em resolves — two different rules This is the part interviews probe, because `em` has two behaviours depending on the property it appears in: 1. **Inside `font-size` itself**, `1em` equals the *parent element's* computed `font-size`. It has to: the element's own font-size is the thing being computed, so it cannot refer to itself. 2. **Inside any other property** — `padding`, `margin`, `width`, `gap`, `border-radius`, `text-indent`, `box-shadow` offsets — `1em` equals the *element's own* computed `font-size`, after that font-size has been resolved. ```css .card { font-size: 1.5em; /* 1.5 x the PARENT's font-size */ padding: 1em; /* 1 x the CARD's own resolved font-size */ } ``` If the parent computes to `16px`, the card's font-size is `24px` and its padding is `24px`, not `16px`. Reading both `1.5em` and `1em` as "relative to the parent" is the single most common mistake here. ## Where compounding comes from Because `font-size: 0.9em` chains off the parent, and the parent's font-size may itself have chained off *its* parent, `em` font sizes **multiply down the tree**: ```css ul { font-size: 0.9em; } ``` A list nested three levels deep computes 0.9 × 0.9 × 0.9 ≈ 0.73 of the original size. Nobody authored a 73% rule; the cascade of relative values produced it. The classic symptom is text that shrinks (or grows) with nesting depth, in a component whose stylesheet looks perfectly reasonable in isolation. Note that `em` compounds *only through inherited font-size*. `padding: 1em` on nested elements does not compound by itself — it compounds only if the font sizes underneath it are also relative and chaining. ## rem and the root `rem` ("root em") always resolves against the computed `font-size` of the root element, which in HTML is `<html>`. Depth is irrelevant, so `1rem` is the same length in a top-level heading and in a element buried ten levels deep. That makes `rem` the natural unit for a type scale and for spacing rhythm — the values stay predictable and a single change on `:root` rescales the whole system. Crucially, if the author never sets a root font-size, the root inherits the **user's** browser font-size preference (commonly `16px`, but a user who needs larger text can raise it). Sizing type in `rem` therefore honours that preference automatically, while `px` type ignores it. One trap: do **not** "fix" the root to a percentage in order to make the math easier, e.g. `html { font-size: 62.5% }` so that `1rem` = `10px`. It still scales with the user preference proportionally, but it silently shrinks any component that relies on the default, and it makes every inherited default in the page smaller than the user asked for. ## When each unit is the right answer - **`rem`** — font sizes, vertical rhythm, container widths, breakpoint-ish sizes. Predictable and user-scalable. - **`em`** — values that should track a component's *own* text size. A button whose `padding: 0.5em 1em` automatically gets roomier when you give it `font-size: 1.25rem` is the point of the unit. Same for icon sizes set in `em` next to text. - **`px`** — things that should not scale with type at all: `1px` borders and dividers, small shadow offsets, and occasionally media-independent details. ## Two gotchas worth knowing **Media query conditions.** `em` and `rem` inside a `@media` condition resolve against the *initial* font-size (the browser default / user preference), not against any `font-size` you set on `:root`. Media queries are evaluated outside the element tree, so there is no element to inherit from. `@media (min-width: 40em)` therefore responds to the user's font preference — which many people consider a feature — but it will not react to `html { font-size: 20px }`. **Unitless `line-height`.** `line-height: 1.5` and `line-height: 1.5em` are not the same. The unitless value inherits as a *ratio*, so each descendant recomputes it against its own font-size; the `em` value computes once and inherits the resulting *length*, which can produce cramped lines on a child with larger text. Prefer unitless line-height.
- If em compounds, why would you ever choose it over rem?Because compounding is sometimes exactly what you want. Padding, gaps and icon sizes expressed in `em` scale with the component's own text, so one `font-size` change resizes the whole component coherently — a small button and a large button share one rule. `rem` would keep the padding fixed while only the text grew, which usually looks wrong.
- Does setting html { font-size: 20px } change what 20em means inside a media query condition?No. Font-relative units in a `@media` condition resolve against the initial font-size — the browser default or the user's preference — not against any author-set value on `:root`. Media queries are evaluated outside the element tree, so there is nothing to inherit from. That is why `em`-based breakpoints track the user's font preference but ignore your root override.
- Why is unitless line-height usually preferred over an em value?A unitless `line-height: 1.5` inherits as a ratio, so every descendant recomputes it against its own font-size. `line-height: 1.5em` computes to a fixed length on the parent and inherits *that length*, so a child with larger text keeps the parent's smaller leading and its lines can overlap or look cramped.
em is like giving a raise as a percentage of whatever your manager earns — chain it down the org chart and the numbers drift. rem is a percentage of one company-wide base salary, so everyone's math agrees.
saying these in an interview costs you the question
- Claims 1em always means 16px
- Says em on padding resolves against the parent's font-size
- Thinks rem compounds through nesting like em
- Believes px and rem differ only in syntax
- Recommends html { font-size: 62.5% } as best practice