CSS Units Explained: px vs rem vs em vs vw
The CSS Units Problem
You are styling a heading and you type `font-size: 24px`. It looks great on your monitor. Then you check it on a phone and it is either too big or too small. A teammate changes the base font size and suddenly half the spacing is off.
CSS has over a dozen units, and picking the right one is not just about personal preference — it directly affects responsiveness, accessibility, and maintainability. Let us go through the ones that matter.
Absolute Units: px
Pixels (`px`) are the simplest CSS unit. One `px` is one device pixel (sort of — high-DPI screens complicate this, but CSS handles the math for you).
```css
.button {
padding: 12px 24px;
border: 1px solid #ccc;
border-radius: 4px;
}
```
When to use px:
- Borders and outlines (you almost always want a consistent 1px or 2px line)
- Box shadows
- Small, fixed-size decorative elements
- When you need pixel-perfect precision
When to avoid px:
- Font sizes (breaks user accessibility settings)
- Spacing and layout in responsive designs
- Anything that should scale with user preferences
Relative Units: rem
`rem` stands for "root em" and is relative to the root element's font size. By default, browsers set the root font size to 16px, so `1rem = 16px`.
```css
html {
font-size: 16px; /* default */
}
h1 {
font-size: 2rem; /* 32px */
margin-bottom: 1rem; /* 16px */
}
p {
font-size: 1rem; /* 16px */
line-height: 1.5rem; /* 24px */
}
```
Why rem is usually the best choice for font sizes:
When a user sets their browser's default font size to 20px (common for users with low vision), all your `rem` values scale proportionally. If you used `px`, those preferences are ignored and your site becomes an accessibility problem.
```css
/* Good: respects user preferences */
.body-text { font-size: 1rem; }
/* Bad: ignores user preferences */
.body-text { font-size: 16px; }
```
Pro tip: Many developers set the root font size to 62.5% so that 1rem = 10px, making mental math easier:
```css
html { font-size: 62.5%; }
/* Now: 1rem = 10px, 1.6rem = 16px, 2.4rem = 24px */
```
Relative Units: em
`em` is relative to the font size of the parent element (or the element itself for font-size properties). This makes it useful for components that should scale proportionally.
```css
.card {
font-size: 1rem; /* 16px base */
padding: 1.5em; /* 24px — relative to this element's font size */
}
.card--large {
font-size: 1.25rem; /* 20px base */
padding: 1.5em; /* 30px — scales with the larger font */
}
```
When to use em:
- Padding and margins within a component that should scale with its own font size
- Media query breakpoints (em-based breakpoints handle zoom better)
- Icon sizing next to text
The compounding problem:
`em` values compound when nested. If a parent has `font-size: 1.2em` and a child also has `font-size: 1.2em`, the child's computed size is 1.44em of the grandparent. This is why `rem` is generally safer for font sizes — it always references the root.
```css
/* Danger: compounding */
.parent { font-size: 1.2em; } /* 19.2px if root is 16px */
.child { font-size: 1.2em; } /* 23.04px — probably not what you wanted */
```
Viewport Units: vw and vh
`vw` and `vh` are percentages of the viewport width and height. `1vw` = 1% of the viewport width.
```css
.hero {
height: 100vh; /* full viewport height */
padding: 5vw; /* scales with viewport width */
}
.hero-title {
font-size: clamp(2rem, 5vw, 4rem); /* responsive font size with limits */
}
```
When to use viewport units:
- Full-screen hero sections (`100vh`)
- Fluid typography that scales with screen size
- Layout elements that should be a proportion of the screen
Watch out for mobile:
On mobile browsers, `100vh` can be taller than the visible area because the address bar is part of the viewport calculation. The newer `dvh` (dynamic viewport height) unit fixes this:
```css
.hero {
height: 100dvh; /* accounts for mobile browser chrome */
}
```
Percentages
Percentages are relative to the parent element's size. They are fundamental for fluid layouts.
```css
.container {
max-width: 1200px;
width: 90%; /* 90% of parent, up to 1200px */
margin: 0 auto;
}
.sidebar {
width: 30%; /* 30% of parent container */
}
```
Which Unit When? A Cheat Sheet
| Use Case | Recommended Unit |
|--------------------------|-----------------|
| Font sizes | rem |
| Component internal spacing| em |
| Layout spacing (margins) | rem |
| Borders & shadows | px |
| Container widths | %, max-width in px/rem |
| Full-screen sections | vh / dvh |
| Fluid typography | clamp(rem, vw, rem) |
| Media queries | em |
The Modern Approach: clamp()
The `clamp()` function is a game changer for responsive design. It sets a minimum, preferred, and maximum value in one line:
```css
/* Font scales fluidly between 1rem and 3rem based on viewport */
h1 {
font-size: clamp(1.5rem, 4vw, 3rem);
}
/* Container padding that adapts to screen size */
.section {
padding: clamp(1rem, 3vw, 3rem);
}
```
This replaces a bunch of media queries with a single, elegant declaration.
Convert Between Units with ToolBox
When you are refactoring a codebase from `px` to `rem`, or need to quickly check what `2.5rem` equals in pixels at a given base size, manual math slows you down.
The [CSS Units Converter](/tools/css-units-converter) on ToolBox lets you:
- Convert between px, rem, em, vw, vh, and percentages instantly
- Set your base font size and viewport dimensions for accurate results
- See all conversions update in real time as you type
It is one of those tools you did not know you needed until you are knee-deep in a responsive redesign. No signup, runs in your browser, free forever.
Want to see more tools and features?