In CSS, why does line-height: 1.5 on a container behave differently for descendants than line-height: 150%?
answer
- inheritance passes computed values, not source text
- numbers stay numbers; percentages become lengths
- unitless line-height re-multiplies per element
- em compounds through nesting for the same reason
- check the ancestor's computed value in DevTools
basics
~20 sInheritance passes the parent's computed value. A unitless line-height computes to the number itself, so each descendant multiplies it by its own font-size; a percentage resolves to a fixed length on the parent, and every descendant inherits that same length.
solid answer
~40 sInheritance transmits the parent's **computed value**, not the text you wrote, and `line-height` computes differently depending on the value type. A unitless `1.5` computes to the number `1.5`, so every descendant inherits the factor and multiplies it by its *own* `font-size`. A `150%` (or `1.5em`) resolves against the parent's font-size at the parent — say 16px, giving a computed `24px` — and every descendant inherits that fixed 24px regardless of how large its own text is. So a 32px heading inside the percentage version gets 24px line boxes and the lines overlap. That is why unitless values are the recommended default for `line-height`. The same computed-value rule explains why `font-size: 1.5em` compounds through nested elements: each level's computed pixel value becomes the next level's basis.
code
html · 7 lines<div style="font-size:16px; line-height:1.5">
<h2 style="font-size:32px">Inherits the number 1.5, computes 48px</h2>
</div>
<div style="font-size:16px; line-height:150%">
<h2 style="font-size:32px">Inherits 24px, so these lines overlap</h2>
</div>go deeper
Know the practical rule: write line-height as a unitless number on containers. Be able to say the percentage version bakes in a fixed pixel height that descendants cannot rescale.
Explain that inheritance transmits computed values, and that line-height's computed value stays a number for a unitless value but becomes an absolute length for a percentage or em.
Work a concrete failure: a 32px heading inside a 16px container with line-height 150% inherits 24px line boxes and overlaps. Connect the same mechanism to compounding em font sizes.
Own it at type-system level: define the scale in rem with unitless line-height at the root, and state where relative units are allowed to compound deliberately versus where they must be flattened.
## The rule: computed values are what travel CSS resolves a declaration through several stages — specified value, computed value, used value. Inheritance happens at the **computed value** stage: a child that inherits a property takes the parent's computed value, already resolved as far as the computed stage takes it. That single sentence explains a family of surprises, because whether a relative unit survives to the children depends entirely on whether it is still relative *at computed-value time*. ## line-height is the textbook case The `line-height` property's computed value depends on the value type: - A `<number>` computes to **the number itself** and stays a number. - A `<length>` computes to an absolute length. - A `<percentage>` is resolved against the element's own `font-size` and computes to an **absolute length**. So consider: ```css .a { font-size: 16px; line-height: 1.5; } /* computed: 1.5 */ .b { font-size: 16px; line-height: 150%; } /* computed: 24px */ ``` Both give 24px line boxes on the container itself. But now put a large child inside: ```css .a h2, .b h2 { font-size: 32px; } ``` Inside `.a`, the child inherits the number `1.5` and computes its own line-height as 32 × 1.5 = **48px** — comfortable. Inside `.b`, the child inherits the already-computed **24px**, which is *smaller than its font-size*: line boxes are shorter than the glyphs, so consecutive lines overlap and descenders collide. `1.5em` behaves exactly like the percentage, because `em` also resolves to an absolute length at computed-value time. This is the whole reason the unitless form is the standard recommendation for any `line-height` set on a container. ## The same rule, other properties **Compounding font-size.** `font-size: 1.5em` resolves against the parent's computed font-size and computes to a length. Nest three such elements inside a 16px root and you get 24px, then 36px, then 54px — each level's computed pixels become the next level's basis. Nesting a list inside a list with `li { font-size: 0.9em }` shrinks text progressively for the same reason. `rem` sidesteps it by always resolving against the root font size. **Percentages that never inherit at all.** `width: 50%` is not inherited, so this question does not arise — but note that percentage *lengths* on inherited properties are the dangerous combination. **Custom properties are the exception that proves the rule.** A custom property's computed value is essentially its token stream, substituted only where it is used. So `--gap: 1.5em` inherited by a child resolves `em` against the *child's* font-size at use time, not the parent's. That asymmetry with ordinary properties trips people up regularly. **currentColor** is another value that resolves per element rather than freezing at the ancestor: it takes the element's own computed `color`. ## How to reason about any property Ask one question: *what is this property's computed value?* Specifications list it explicitly in each property's formal-definition table ("Computed value: the specified number, or an absolute length"). If the computed value is still relative or keyword-shaped, descendants re-resolve it against their own context. If it has already been flattened to an absolute length or colour, descendants inherit that frozen result. ## Practical guidance - Set `line-height` as a unitless number, especially on `html`, `body` or any component root. - Use lengths or percentages for `line-height` only on a leaf element whose descendants you do not care about, such as a single-line badge where you want an exact box height. - Prefer `rem` over `em` for `font-size` on anything that can nest, unless the compounding is the effect you want (progressively smaller nested lists, for example). - When something inherits a value you did not expect, check the *computed* value in DevTools on the ancestor rather than reading your source — the computed value is what actually travelled down.
- Why does font-size: 1.5em compound when you nest elements?Because `em` resolves against the parent's computed `font-size` and computes to an absolute length. Each nesting level therefore takes the previous level's already-multiplied pixel value as its basis: 16px, 24px, 36px, 54px. `rem` avoids this by resolving against the root element's font-size instead of the parent's, so it stays flat no matter how deeply you nest.
- Custom properties containing em behave differently from ordinary properties — why?A custom property's computed value is basically its token stream; the relative unit is not resolved until the value is substituted into a real property. So `--gap: 1.5em` declared on a parent and used by a child resolves against the *child's* font-size, whereas an inherited `padding: 1.5em` would have been frozen to pixels on the parent. Same inheritance mechanism, different point of resolution.
- Is there a legitimate case for a percentage or length line-height?Yes — on a leaf element where you want an exact line-box height and nothing inherits from it. A single-line badge, a button label, or an icon-aligned chip can reasonably use `line-height: 24px` so the box height is deterministic. The rule of thumb is: unitless on anything containers pass down, absolute only where the value stops.
saying these in an interview costs you the question
- Says 1.5 and 150% are just two spellings of the same thing
- Thinks children re-resolve an inherited percentage themselves
- Believes inheritance passes the declared source value
- Cannot explain why em font sizes compound when nested
- Sets line-height in px on the body element by default