CSS Units Explained: px, rem, em, vw, vh, and When to Use Each
June 10, 2026 · 6 min read
CSS Units Explained: px, rem, em, vw, vh, and When to Use Each
CSS has over a dozen length units, and using the wrong one in the wrong context causes brittle layouts, accessibility failures, and mobile display bugs. The good news: once you understand the categories and the tradeoffs, the rules become intuitive.
Absolute Units
Absolute units map to a fixed physical or logical size, regardless of anything else on the page.
px (pixels) — The most familiar unit. In CSS, 1px is not necessarily one device pixel — on a retina display, 1px might map to 2 or 3 physical pixels. What px really means is a single CSS pixel, defined by the W3C as 1/96th of an inch at arm's length. For practical purposes: px gives you predictable, fixed sizes.
border: 1px solid #e2e8f0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
pt (points) — 1pt = 1/72 inch. Comes from print typography. Avoid on screens — it has no meaningful advantage over px for digital output and creates confusion.
cm, mm, in — Literal centimeters, millimeters, inches. Only relevant for print stylesheets (@media print). On screen, 1in = 96px regardless of the monitor's actual DPI.
Relative Font Units
These units scale relative to font sizes, making them powerful for responsive and accessible typography.
em — Relative to the parent element's font-size. This is where it gets dangerous: em values compound through nested elements.
body { font-size: 16px; }
.parent {
font-size: 1.25em; /* 16 * 1.25 = 20px */
}
.parent .child {
font-size: 1.25em; /* 20 * 1.25 = 25px — NOT 20px! */
}
This compounding ("em cascade") is the most common CSS pitfall for developers learning relative units. Use em for spacing that should scale with the local text size (padding, margins inside a component), but avoid it for font-size unless you're explicitly controlling the cascade.
rem (root em) — Relative to the root element's (<html>) font-size. No compounding, ever. The default browser root font-size is 16px, so 1rem = 16px unless overridden.
:root { font-size: 16px; } /* 1rem = 16px everywhere */
h1 { font-size: 2rem; } /* 32px */
p { font-size: 1rem; } /* 16px */
small { font-size: 0.875rem; } /* 14px */
rem is the preferred unit for font sizes and most layout spacing because it respects the user's browser font preference. If a user sets their browser default to 20px (common for accessibility needs), your entire layout scales proportionally. px font sizes bypass this preference entirely.
ch — Width of the 0 (zero) character in the current font. Useful for controlling text line length:
.prose { max-width: 65ch; } /* ~65 characters per line — readable measure */
ex — Height of the lowercase x in the current font. Rarely used in practice.
Viewport Units
Viewport units are relative to the browser's viewport size, making them ideal for full-screen layouts.
vw (viewport width) — 1vw = 1% of the viewport width. 100vw = full viewport width.
vh (viewport height) — 1vh = 1% of the viewport height. 100vh = full viewport height.
/* Full-screen hero section */
.hero {
width: 100vw;
height: 100vh;
}
The mobile 100vh problem: On mobile browsers, 100vh includes the address bar height — so the page overflows behind the browser chrome. This caused layout issues for years. The fix is the new dynamic viewport units.
svh (small viewport height) — The viewport height when the browser chrome (address bar, nav) is fully visible. Smallest possible viewport.
lvh (large viewport height) — The viewport height when the browser chrome is hidden (user scrolled down). Largest possible viewport.
dvh (dynamic viewport height) — Dynamically updates as the browser chrome shows/hides. The correct choice for full-screen mobile layouts:
.hero {
/* Fallback for older browsers */
height: 100vh;
/* Correct on modern mobile */
height: 100dvh;
}
vmin / vmax — vmin is the smaller of vw and vh; vmax is the larger. Useful for responsive sizing that adapts to orientation.
Container Query Units
New in 2023, now baseline across all modern browsers:
cqw (container query width) — 1% of the containing element's width (requires container-type on the parent).
cqh — 1% of the containing element's height.
.card-container {
container-type: inline-size;
}
.card-title {
font-size: clamp(1rem, 4cqw, 1.5rem); /* scales with card width */
}
Container units enable truly component-scoped responsive design, independent of the viewport.
When to Use What
| Property | Recommended Unit | Why |
|---|---|---|
font-size |
rem |
Scales with user browser preference |
Spacing (padding, margin) |
rem or em |
rem for consistent scale; em for component-relative spacing |
border, outline, box-shadow |
px |
Fine details should be crisp and fixed |
| Full-screen height | dvh (+ vh fallback) |
Avoids mobile browser chrome issues |
| Full-width layout | vw or % |
Relative to viewport or parent |
| Text line length | ch |
Directly tied to character count |
| Responsive font scaling | clamp() with vw |
Smooth scaling between breakpoints |
| Print stylesheets | pt, cm, mm |
Physical measurements only |
Fluid Typography with clamp()
clamp(min, preferred, max) is the modern way to scale typography smoothly between viewport sizes without media query breakpoints:
h1 {
font-size: clamp(1.75rem, 4vw, 3rem);
/* At 400px viewport: ~1.75rem (minimum) */
/* At 800px viewport: 4vw = 32px = 2rem */
/* At 1200px viewport: ~3rem (maximum) */
}
This replaces verbose breakpoint-based font scaling with a single line. The CSS Clamp Calculator generates the exact formula based on your min/max sizes and breakpoints.
Common Mistakes
Using px for font-size — This is an accessibility failure. Users who increase their browser's default font size (a common accessibility accommodation) will see no change on your site. Every font-size: 16px should be font-size: 1rem.
The em nesting trap — Nesting elements that all use em for font-size causes exponential scaling. A font-size: 1.2em inside another font-size: 1.2em gives you 1.44× the root size, not 1.2×. Switch to rem to eliminate this entirely.
Using 100vh on mobile — Without dvh (and a vh fallback), full-screen layouts overflow behind the address bar on iOS and Android. Use height: 100dvh for elements that must truly fill the screen.
Mixing em and rem inconsistently — Pick a convention. The most common is: rem for all font-size declarations, em for padding/margin inside components so they scale with local font size.
Quick Reference
Use the px to rem Converter to translate pixel values from designs into rem equivalents. For a broader range of unit conversions — including em, vw, and percent calculations — the CSS Unit Converter handles the math. For fluid typography, the CSS Clamp Calculator generates the clamp() formula for your exact requirements.
CSS units are not a style choice — they're a structural decision that affects accessibility, responsive behavior, and maintainability. Use rem for text, px for hard edges, and dvh/vw for viewport-relative layouts, and you'll avoid 90% of the gotchas.