CSS lets you express lengths in many different units. They’re not interchangeable — each one is relative to something different, and that something determines how the value behaves at different screen sizes, zoom levels, and contexts. The tool above converts between units in your browser; nothing leaves your machine.
The unit families
| Family | Units | Relative to |
|---|---|---|
| Absolute | px, pt, pc, cm, mm, in | Fixed (in CSS pixels, not physical pixels) |
| Font-relative | em, rem, ex, ch | A font size somewhere in the cascade |
| Viewport-relative | vh, vw, vmin, vmax, vi, vb | The viewport dimensions |
| Container-relative | cqw, cqh, cqi, cqb (newer) | The size of a containing element |
| Percentage | % | The corresponding property of the parent |
Two units that produce the same number of CSS pixels in one context can produce different numbers in another. That’s the point.
px — the unit that isn’t really pixels
1px in CSS is not 1 device pixel. It’s 1/96 of an inch in CSS’s reference coordinate system. On a high-DPI display, the browser maps each CSS pixel to multiple device pixels (e.g., 2× on a Retina display means 1 CSS px = 4 device px). On any display, when the user zooms, CSS px scales with the zoom.
px is the most-commonly-used unit and the easiest to reason about: font-size: 16px means the text is 16 reference units tall, and 16 reference units is the same on every device.
The other absolute units (pt, pc, cm, mm, in) are defined relative to px: 1pt = 1.333px, 1in = 96px. They’re useful in print stylesheets; rare elsewhere.
em — relative to the current element’s font-size
1em equals the computed font-size of the current element.
.parent { font-size: 20px; }
.parent .child { padding: 1em; }
/* .child padding = 20px (its font-size is inherited from .parent) */
.parent .child { font-size: 14px; padding: 1em; }
/* .child padding = 14px (its own font-size, not inherited) */
The trap: em compounds. A nested element whose parent uses em for font-size ends up with multiplied sizes. font-size: 1.2em three levels deep is 1.2 × 1.2 × 1.2 = 1.728× the root size, not 1.2×.
em is appropriate for properties that should scale with the element’s text — the padding around a button should grow when the button’s text grows, for example.
rem — relative to the root font-size
1rem equals the font-size of the <html> element. By default that’s 16px.
:root { font-size: 18px; }
.anywhere { padding: 1rem; }
/* padding = 18px, regardless of nesting */
rem is the modern default for most layout work because it doesn’t compound. Setting :root { font-size: 16px; } and using rem everywhere means the user can change one number to scale the whole site.
% — relative to the parent’s same property
.parent { width: 400px; }
.parent .child { width: 50%; }
/* width = 200px (50% of parent width) */
Different properties can use percentages with different parent references:
width: 50%— 50% of parent’s width.padding: 10%— 10% of parent’s width (always width, even for top/bottom padding).font-size: 80%— 80% of parent’s font-size (similar toem).line-height: 150%— 150% of element’s font-size.
Percentage is intuitive for layout but surprising for properties whose parent reference isn’t obvious. Read the spec for each.
vh, vw — relative to the viewport
1vh= 1% of the viewport height.1vw= 1% of the viewport width.1vmin= the smaller ofvhorvw.1vmax= the larger.
Useful for elements that should always fit a portion of the screen — full-bleed sections, hero images, modal overlays. The trap on mobile: viewport height is contentious. The browser’s URL bar and bottom nav appear and disappear as the user scrolls; “100vh” can be the viewport size with the nav visible (in some browsers) or without (in others). The newer units svh, lvh, dvh (small/large/dynamic viewport height) clarify which:
| Unit | Definition |
|---|---|
100vh | Inconsistent across browsers; legacy |
100svh | Smallest possible viewport (URL bar + nav both visible) |
100lvh | Largest possible viewport (URL bar + nav both hidden) |
100dvh | Dynamic — current viewport, changes on scroll |
For “fill the screen exactly” today, 100dvh is usually what authors want.
ch — relative to the “0” character’s width
1ch equals the width of the digit 0 in the current font. Useful for setting input widths that fit a fixed number of characters:
input.zip-code { width: 6ch; }
In a monospace font, 1ch is the same for every character. In a proportional font, characters narrower than 0 (l, i, 1) take less space; wider ones (m, w) take more. The unit is approximate for proportional fonts.
When to use which
| Use case | Recommended unit |
|---|---|
| Body font size | rem (so user-zoom of the root scales everything) |
| Button padding | em (scales with the button’s text) |
| Container width | % or rem |
| Viewport-fitting hero | dvh/dvw |
| Border width | px (1px borders should always be 1px) |
| Media query breakpoints | em or rem (scales with user-zoom; px doesn’t) |
| Print stylesheet | pt or mm |
| Input width by character count | ch |
| Icon size that scales with text | em |
The trend over the last decade: less px, more rem and viewport units, more responsive-by-default sizing.
Common pitfalls
- Using
pxfor media queries. Browsers historically had inconsistent behavior with px-based media queries when the user zoomed.em-based media queries scale with user font preferences and are now the standard. - Compounding
emaccidentally. A1.2emfont-size on a deeply-nested element multiplies by every ancestor’sem. Useremunless the compounding is intentional. 100vhnot fitting on mobile. Discussed above; use100dvh.- Mixing
ptandpx. They’re not equivalent;1pt = 1.333px. Pick one for a project. - Forgetting that
%references different parent properties for different properties. Padding-top’s percentage uses parent width, not parent height. This trips up authors writing aspect-ratio padding.
For other CSS-related tools, see CSS formatter, CSS minifier.