The Three Categories of CSS Units
CSS length units fall into three groups: absolute, font-relative, and viewport-relative. Each group has a different frame of reference, and that determines when to use them.
Absolute Units
- Border widths (1px, 2px borders look crisp)
- Box shadows and blurs
- Values that should never scale with font size
- Media query breakpoints (though rem-based breakpoints are gaining traction)
**Avoid px for:** font sizes and spacing that should respond to the user's browser font preference. A user who sets their browser to 20px base font size (for accessibility) will find that px-based text ignores their preference.
Font-Relative Units
**rem (root em)** — relative to the root element's (<html>) font size. The browser default is 16px, so 1rem = 16px by default, but respects the user's browser preference.
This is the best unit for: font sizes, most spacing (padding, margin, gap), and component sizing that should scale with the user's text preference. Using rem throughout makes your site accessible to users who have set a larger default font size.
**em** — relative to the *current element's* font size (or the nearest parent's font size for properties like margin and padding). This creates a cascade:
css
.card { font-size: 1.25rem; }
.card p { margin-bottom: 1em; } /* 1em = 1.25rem here */
Use em for: spacing that should scale with an element's own font size (like letter-spacing, line-height, and padding inside a component). Avoid em for font-size on nested elements — it compounds in confusing ways.
Viewport-Relative Units
**vw (viewport width)** — 1vw = 1% of the viewport width. **vh (viewport height)** — 1vh = 1% of the viewport height.
Use vw/vh for: full-screen hero sections (height: 100vh), fluid typography that scales with screen width (font-size: 4vw), sticky elements that should fill the screen.
**Gotcha:** 100vh on mobile browsers includes the browser chrome (address bar), causing the page to be taller than the visible area. Use 100dvh (dynamic viewport height) instead — supported in all modern browsers since 2023.
**svh/dvh/lvh** — the new viewport units. svh (small viewport height) = smallest possible height (mobile with bars visible). dvh (dynamic) = updates as bars appear/disappear. lvh (large) = largest possible height.
**ch** — width of the "0" character in the current font. Useful for constraining text containers: max-width: 65ch creates readable line lengths without needing to know the exact pixel width.
The Decision Framework
| Situation | Unit to use |
|---|---|
| Font sizes | rem |
| Spacing (padding, margin, gap) | rem |
| Component internal spacing that scales with text | em |
| Border widths | px |
| Full-screen sections | 100dvh |
| Fluid typography | clamp(1rem, 2.5vw, 2rem) |
| Readable text containers | 60-75ch |
| Media query breakpoints | rem or px (consistent, either works) |
clamp(): The Best of Both Worlds
clamp(min, ideal, max) lets you set fluid values that scale between a minimum and maximum:
css
font-size: clamp(1rem, 2.5vw, 2rem);
This means: never smaller than 1rem, scale with viewport width at 2.5vw, never larger than 2rem. This replaces the need for many media query breakpoints for typography.
Converting Between Units
NoxaKit's CSS Unit Converter instantly converts between px, rem, em, vw, vh, and percentages. The Tailwind Spacing Converter maps px values to the nearest Tailwind spacing scale class — useful when migrating from bespoke CSS to a utility framework.