Topic 3.2
Relative Units
In one line
Relative units measure against something else: em against the font size, rem against the root font size, % against a property-specific reference, and ch/ex against the font's own letters; choosing the right reference makes designs scale with the reader.
Think of it like this
Telling a friend "cut the cake into slices half as wide as your hand". The slice size depends on whose hand it is. A relative unit works the same way: 2em means "twice the current text size", so it gets bigger or smaller when the text does.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Relative unit
- A unit whose real size depends on something else, like the text size or the parent's width.
- em
- One times the font size. On
font-sizeit uses the parent's size; on other properties, the element's own size. - rem
- "Root em": one times the font size of the
<html>element, 16px by default. - Root element
- The outermost element of the page,
<html>. CSS can select it ashtmlor:root. - Compounding
- When sizes multiply as you nest elements, so
1.2eminside1.2embecomes 1.44 times the start. - Containing block
- The box a percentage is measured against, usually the content area of the parent element.
- ch
- The width of the character
0in the current font. Handy for line lengths. - x-height (ex)
- The height of lowercase letters like
xin the current font. - Computed value
- The final value the browser works out for a property, often turned into pixels.
Step by step
01rem: one reference for the whole page
Set sizes in rem and they all hang off one number, the root font size. If the reader sets their browser's default text to 20px, 1rem becomes 20px, 1.5rem becomes 30px, and the whole design grows in proportion.
That is why you should not set html { font-size: 16px; }: it would replace the reader's choice with a fixed number. Leave the root alone, or set it as a percentage like 100%.
h1 { font-size: 2rem; } /* 32px by default */
p { font-size: 1rem; } /* 16px by default */
.small { font-size: 0.875rem; } /* 14px by default */
section { padding: 1.5rem; } /* 24px by default */02em: grows with its own component
Give a button padding: 0.5em 1em. A normal button with 16px text gets 8px by 16px padding. Make a large button with font-size: 1.5rem (24px) and its padding becomes 12px by 24px automatically, so it keeps the same shape.
.btn {
font-size: 1rem;
padding: 0.5em 1em; /* scales with this button's own text */
border-radius: 0.4em;
}
.btn.large { font-size: 1.5rem; } /* padding and radius follow */03Watch em compound when you nest
em on font-size multiplies the parent's size. A list item at 1.2em inside another at 1.2em inside another ends up at 16 × 1.2 × 1.2 × 1.2 = 27.648px. With rem every level stays at 19.2px.
04% depends on the property
In a parent that is 400px wide and 200px tall, a child with width: 50% is 200px wide. height: 50% is 100px, because the parent's height is fixed. But padding-top: 10% is 40px: vertical padding and margin percentages are measured against the width, not the height. That surprise is behind the classic "padding-top: 56.25% for a 16:9 box" trick, which aspect-ratio replaces today (CSS Phase 9).
05ch and ex: measure with the font itself
max-width: 65ch limits a paragraph to about 65 characters per line, which is easy to read. Because ch comes from the font, the limit stays right when the font or size changes.
ex is rare, but useful for nudging small things relative to lowercase letters, like an icon's vertical position next to text.
article p { max-width: 65ch; }
input.zip { width: 7ch; font-family: monospace; } /* fits 7 characters */Try it yourself
- 1
Predict the fourth level
In the first example, add a fourth nested
<li>inside each list (em level 4,rem level 4). Predict both sizes before running. (Hint: multiply 27.648 by 1.2.) - 2
Change the root
In the second example, add
html { font-size: 125%; }to the CSS. Predict the new numbers, then run. Everything grows by 1.25 because every size hangs offrem. This is what happens for a reader who sets a 20px default font. - 3
Give the parent an auto height
In the third example, delete
height: 200px;from.parent. Predict whatheight: 50%becomes now. Run it: the percentage has nothing fixed to measure against, so it behaves likeautoand the console shows the child's natural height.
Code & diagrams
Each em level multiplies by 1.2 again; each rem level stays at 1.2 × 16px.
Preview
Console
Nothing logged yet.Expected console output
em level 1 19.2px
em level 2 23.04px
em level 3 27.648px
rem level 1 19.2px
rem level 2 19.2px
rem level 3 19.2pxOnly font-size differs between the buttons. The padding follows each button's own text size.
Preview
Console
Nothing logged yet.Expected console output
Normal: font 16px padding 8px 16px
Large: font 24px padding 12px 24px
Small: font 12px padding 6px 12pxpadding-top: 10% is 10% of the parent's WIDTH (400px), not its height.
Preview
Console
Nothing logged yet.Expected console output
width 50% = 200px
height 50% = 100px
padding-top 10% = 40pxChange the font-size of .measure to 1.5rem: the box gets wider too, because ch grows with the font.
Preview
Console
Nothing logged yet.Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Nested em font sizes run away
Give li { font-size: 1.2em; } and build a menu with three levels of nested lists.
Break #2
height: 100% does nothing
Set .panel { height: 100%; } inside a <div> that has no height set.
Myth vs fact
Myth
1rem is always 16px.
Fact
It is 16px only while the root font size is the browser default and the reader hasn't changed it. A reader with a 20px default gets 1rem = 20px, which is the whole point.
Myth
em always means the parent's font size.
Fact
Only on the font-size property. On padding, margin, width and the rest, em uses the element's own computed font size.
Myth
padding-top: 10% is 10% of the parent's height.
Fact
Vertical padding and margin percentages use the containing block's width. Only height, top and bottom use its height.
Myth
Setting html { font-size: 62.5% } is required to use rem.
Fact
It is an old trick to make 1rem = 10px for easy maths. It still respects the reader's setting, but it forces you to set every font size again. Thinking in 16ths (0.875rem = 14px) works fine.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Inside media queries,
emandremrefer to the browser's initial font size (usually 16px), not to anything you set onhtml, because media queries are evaluated before your styles. Breakpoints inem(for example@media (min-width: 40em)) also respond to the reader's default text size in most browsers. - ▸
line-heightpercentages andemvalues are computed to a pixel length on the element and that pixel value is inherited, which causes cramped lines in children with bigger text. A unitlessline-height: 1.5is inherited as the ratio instead, which is why it is the recommended form (CSS Phase 4). - ▸
Newer font-relative units exist:
lh(the element's line height) andrlh(the root's),cap(capital letter height),ic(width of the CJK water ideograph 水). They are useful for vertical rhythm and East Asian text; check support before relying on them. - ▸
chuses the advance width of0; in proportional fonts most letters are narrower, so65chholds a few more than 65 average characters. If the font hasn't loaded yet,chis measured with the fallback font and changes when the web font arrives, which can shift layout (see CSS Phase 4 — Web Fonts).
Remember this
- 1
A relative unit is a unit whose size comes from something else: a font size, the parent element's width, or the size of a letter. The browser works out the real pixel size for every element. This final pixel number is the computed value (Topic 0.4 showed it in DevTools' Computed pane).
- 2
**
em** is relative to a font size. On thefont-sizeproperty itself,1emmeans the parent's font size, sofont-size: 1.5emis "one and a half times my parent's text". On every other property (padding,margin,width,border-radius…),1emmeans the element's own font size. Because each element'semfont size builds on its parent's, nested elements compound:1.2eminside1.2eminside1.2emis1.728times bigger. - 3
**
rem(root em) is always relative to the font size of the root element**,<html>. Browsers default it to16px, but readers can change that default in their browser settings. So1remis usually16px,1.5remis24px, and everyremgrows when a reader asks for bigger text.remnever compounds, which makes it the safest default for font sizes and for spacing. - 4
**
%** means "a percentage of some reference", and the reference depends on the property. Forfont-size, it is the parent's font size (likeem). Forwidth, and forpaddingandmarginon all four sides, it is the width of the containing block (usually the parent's content box). Forheight, it is the containing block's height, but only if that height is fixed; otherwiseheight: 50%acts likeauto. Fortransform: translate(), it is the element's own size. - 5
**
ch** is the width of the digit0in the element's current font, and **exis the font's x-height** (roughly the height of a lowercasex). They are tied to the actual font.max-width: 65chkeeps paragraphs to a comfortable reading line of about 60–75 characters. In a monospace (fixed-width) font,1chis exactly one character, sowidth: 20chfits 20 characters. - 6
Which to choose:
remfor font sizes and the page's spacing scale;emfor things that should grow with their own component's text (button padding, icon size next to text, a heading's margin);%for fractions of the parent's width;chfor line length and inputs sized to their content;pxfor borders and hairlines. Topic 3.3 adds viewport units and Topic 3.7 mixes them all withclamp().
Explain it without notes
Explain the difference between em and rem, including what em refers to on font-size versus on padding.
Why are rem font sizes better for accessibility than px font sizes?
What does a percentage refer to for width, height, padding-top and font-size?
When would you choose em over rem on purpose?
Practice
Write a type scale in rem for h1 (40px), h2 (28px), p (16px) and .caption (13px) at the default root size.
Make an .icon span sit next to text and always be the same height as that text, whatever the text size.
Make a paragraph never wider than 60 characters and center it on the page.
Trade-offs
- ↔
remis predictable and accessible but ignores the component's context;emadapts to context but compounds when nested. - ↔
%widths adapt to the parent but depend on knowing what the containing block is;chadapts to the font but changes when the font swaps.
Done when you can
I can convert a pixel size to
remat the default root size.I can explain why nested
emfont sizes compound and how to avoid it.I can say what
%refers to for width, height, padding and font-size.I can size a line of text with
ch.I can choose between
px,rem,em,%andchfor a given job.