CSS units.
Every CSS unit, grouped by what it's measured against. Tap any to copy it.
Absolute
| Unit | Equals | Notes |
|---|---|---|
| px | 1 CSS pixel | The everyday absolute unit |
| pt | 1/72 inch | Print; common in typography |
| in | 96px | Inch — print |
| cm | 37.8px | Centimetre — print |
| mm | 3.78px | Millimetre — print |
Font-relative
| Unit | Relative to | Notes |
|---|---|---|
| em | Element's font size | Compounds when nested |
| rem | Root (html) font size | Doesn't compound — preferred |
| ch | Width of the '0' glyph | Handy for text column widths |
| ex | x-height of the font | Rarely used |
Viewport-relative
| Unit | Relative to | Notes |
|---|---|---|
| vw | 1% of viewport width | Responsive widths |
| vh | 1% of viewport height | Full-height sections |
| vmin | 1% of the smaller side | Smallest viewport dimension |
| vmax | 1% of the larger side | Largest viewport dimension |
| % | The parent / context | Percentage of the container |
Grid, angle & time
| Unit | Measures | Notes |
|---|---|---|
| fr | A fraction of free space | CSS Grid track sizing |
| deg | Degrees | Rotations and gradients |
| turn | 1 full turn = 360deg | Rotations |
| s | Seconds | Animations and transitions |
| ms | Milliseconds | Animations and transitions |
Absolute vs relative
CSS units split into two camps. Absolute units like px are fixed sizes — a pixel is a pixel regardless of context — which makes them predictable but unresponsive. Relative units are measured against something else, which is what makes layouts adapt. The two that matter most for type are em and rem: em is relative to the element's own font size and compounds when you nest elements, while rem is always relative to the root font size, so it stays predictable — which is why rem is the usual choice for scalable typography and spacing. For layout, the viewport units (vw, vh) size things against the screen, and fr distributes leftover space across CSS Grid tracks. A good default is rem for type and spacing, % or fr for layout widths, and px only where a fixed size is genuinely wanted, like a 1px border.
em vs rem, with the numbers
This is the distinction that causes the most confusion, and one worked example settles it. Assume the browser default root size of 16px.
rem is always measured against the root element, so 1rem is 16px anywhere in the document, no matter how deeply nested. em is measured against the current element's own font size, which means it compounds through nesting: a <div> at font-size: 1.5em renders at 24px, and a child inside it also set to 1.5em renders at 36px, not 24px. Nest a third and you are at 54px. That runaway growth in nested lists and menus is almost always an em problem.
The practical split most codebases settle on: rem for font sizes, so type scales predictably from one place, and em for padding, margins and border-radius on a component, so its spacing scales with its own text. A button with padding: 0.5em 1em keeps proportional padding whether it is a small button or a large one, with no extra rules.
Why px is an accessibility problem for type
Users can raise the default text size in their browser settings, and a meaningful number do. Sizes in rem and em respect that preference and scale up; a size in px does not, so text set in pixels stays small for someone who explicitly asked for larger text. Browser zoom scales everything either way, but the font-size preference only reaches relative units.
That is the argument for relative units on anything textual. Pixels remain entirely reasonable for things that should not scale with text — hairline borders, fine shadow offsets, a 1px rule.
You may also meet the 62.5% trick: setting html { font-size: 62.5% } makes 1rem equal 10px, so the mental arithmetic becomes trivial. It still honours the user's preference proportionally, but it does mean anything you forget to size explicitly inherits a small default, so use it deliberately rather than by habit.
Choosing a unit quickly
- Font size →
rem. Predictable, and it respects the user's text-size setting. - Padding and margin inside a component →
em, so spacing tracks that component's text. - Borders and hairlines →
px. These should not grow with text. - Full-viewport sections →
vhandvw, with the caveat that mobile browser chrome makes100vhovershoot;dvhis the modern fix. - Widths inside a container →
%, measured against the parent. - Grid tracks →
fr, which splits whatever space is left over. - Line length →
ch, roughly the width of a "0", which makes a max-width of about65cha good measure for readable prose.