CSS units can be confusing. Should you use px or rem? When does vw make sense? What about ch and ex? Picking the right unit makes the difference between a layout that breaks and one that gracefully adapts to every screen size.
This reference breaks CSS units into two categories — absolute and relative — with clear examples of when to use each. Bookmark this page for your next responsive design project.
💡 Quick Rule of Thumb
Use rem for font sizes, px for borders/shadows, % for widths, vw/vh for full-screen sections, and em for spacing relative to the current font size.
Absolute Units
Absolute units are fixed-length values. They don't scale with the viewport, parent element, or font size. Use them for print stylesheets, borders, and situations where precision matters regardless of screen size.
| Unit | Name | Relative to | Best For |
|---|---|---|---|
| px | Pixel | 1px = 1/96th of 1 inch (screen) | Borders, shadows, small precise spacing, images |
| pt | Point | 1pt = 1/72nd of 1 inch | Print stylesheets, traditional typography |
| pc | Pica | 1pc = 12pt = 1/6th of 1 inch | Print layouts (rarely used on web) |
| cm | Centimeter | 1cm = 37.8px (approx) | Print stylesheets, physical measurements |
| mm | Millimeter | 1mm = 1/10th of 1cm | Print stylesheets |
| in | Inch | 1in = 96px | Print stylesheets |
| Q | Quarter-millimeter | 1Q = 1/40th of 1cm | Print, Japanese/CJK layouts |
⚠️ When Not to Use px
Avoid pxfor font sizes in modern responsive design. Users who change their browser's default font size will see no change in pixel-sized text, which creates accessibility issues. Use rem instead — it respects the user's font size preference.
Relative Units
Relative units scale based on the context — the viewport, parent element, or root font size. They are the foundation of responsive and accessible design.
Font-Relative Units
| Unit | Name | Relative to | Best For |
|---|---|---|---|
| em | Em | Font size of the parent element | Spacing, padding, margins relative to text size |
| rem | Root Em | Font size of the root (<html>) element | Font sizes, spacing (accessibility-friendly) |
| ch | Character | Width of the '0' character in current font | Input widths, line length constraints |
| ex | X-height | Height of the 'x' character in current font | Vertical alignment, inline spacing |
| ic | Ideograph | Width of CJK ideograph character | Chinese/Japanese/Korean text layouts |
| lh | Line height | Computed line-height of the element | Vertical rhythm, consistent spacing |
| rlh | Root line height | Computed line-height of the root element | Global vertical rhythm |
Viewport-Relative Units
| Unit | Name | Relative to | Best For |
|---|---|---|---|
| vw | Viewport Width | 1% of viewport width | Full-width elements, hero sections, fluid typography |
| vh | Viewport Height | 1% of viewport height | Full-height sections, modal overlays, sticky elements |
| vmin | Viewport Minimum | 1% of the smaller viewport dimension (width or height) | Responsive square elements, safe sizing for all orientations |
| vmax | Viewport Maximum | 1% of the larger viewport dimension (width or height) | Full-screen backgrounds, decorative elements |
| svw / svh | Small Viewport | Viewport size excluding dynamic browser chrome | Mobile-safe full-screen layouts |
| lvw / lvh | Large Viewport | Viewport size including potential browser chrome | When you want the full device screen regardless of UI |
| dvw / dvh | Dynamic Viewport | Dynamically updates as browser chrome shows/hides | Works like 100vh but handles mobile toolbar changes |
⚠️ Viewport Unit Gotcha on Mobile
On iOS Safari, 100vh includes the browser toolbar height, which collapses when scrolling. This causes content to be taller than expected. Use 100dvh (dynamic viewport height) or 100svh (small viewport height) for reliable full-height sections on mobile.
Percentage Unit
| Unit | Name | Relative to | Best For |
|---|---|---|---|
| % | Percentage | Depends on property: width → parent width, height → parent height, font-size → parent font-size, padding/margin → parent width (even for vertical padding) | Fluid layouts, responsive widths, aspect ratios |
💡 Percentage Padding Quirk
When using padding-top: 50% or padding-bottom: 50%, the percentage is calculated from the parent's width, not height. This is actually useful for creating fixed-aspect-ratio boxes (like a 16:9 container) without JavaScript.
When to Use Each Unit
The table below maps common CSS properties to their recommended units.
| Property | Recommended Unit | Why |
|---|---|---|
| font-size | rem | Respects user's browser font size setting. Avoids compounding issues of em. |
| padding / margin | rem | Consistent spacing regardless of nested font sizes. |
| width / max-width | % or rem | % for fluid layouts, rem for fixed content widths (e.g., article max-width). |
| height | auto (avoid fixed) | Let content determine height. Use min-height with vh for full-screen sections. |
| border-width | px | Borders should be crisp and not scale with text size. |
| border-radius | px or rem | px for small radii, rem for larger rounded corners that should scale. |
| box-shadow | px | Shadow blur and spread should stay crisp. |
| line-height | unitless (e.g., 1.5) | Unitless values scale proportionally with font-size changes. |
| gap | rem | Grid/flexbox gaps should scale with content size. |
| hero / full-screen | dvh | Dynamic viewport handles mobile browser toolbar correctly. |
| fluid typography | clamp() | Combine rem + vw with min/max bounds (e.g., clamp(1rem, 2.5vw, 2rem)). |
| icon sizing | em | Icon scales with surrounding text size automatically. |
Practical Examples
Fluid Typography with clamp()
The clamp() CSS function lets you set a font size that scales between a minimum and maximum value. This is the modern way to do responsive typography without media queries.
/* Fluid heading: scales from 1.5rem to 3rem between 320px and 1200px viewports */
h1 {
font-size: clamp(1.5rem, 1rem + 2.5vw, 3rem);
line-height: 1.1;
}
/* Fluid body text */
p {
font-size: clamp(0.875rem, 0.75rem + 0.5vw, 1.125rem);
line-height: 1.6;
}Full-Height Hero Section (Mobile-Safe)
.hero {
/* dvh = dynamic viewport height — handles mobile browser toolbar */
min-height: 100dvh;
/* Fallback for older browsers */
min-height: 100vh;
min-height: 100svh;
display: flex;
align-items: center;
justify-content: center;
}Consistent Spacing with rem
:root {
/* Set root font size. Browser default is 16px = 1rem */
font-size: 100%; /* Respects user preferences */
}
.card {
padding: 1.5rem; /* = 24px at default font size */
margin-bottom: 1rem; /* = 16px */
border-radius: 0.5rem; /* = 8px */
gap: 0.75rem; /* = 12px grid gap */
}
h2 {
font-size: 1.25rem; /* = 20px */
margin-bottom: 0.5em; /* relative to h2 font size */
}16:9 Aspect Ratio Box
.aspect-16-9 {
/* Padding % is calculated from parent width */
/* 9/16 = 56.25% */
width: 100%;
padding-bottom: 56.25%;
position: relative;
overflow: hidden;
}
.aspect-16-9 > * {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}Perfectly Centered Modal
.modal-overlay {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
}
.modal {
width: min(90vw, 600px); /* 90% of viewport width, max 600px */
max-height: 90dvh; /* 90% of dynamic viewport height */
overflow-y: auto;
padding: 2rem;
background: #fff;
border-radius: 0.75rem;
}calc() in Practice
The calc()function lets you mix units freely. It's extremely useful for fluid layouts where you need arithmetic operations on CSS values.
/* Sidebar + main: 250px sidebar, rest is main */
.main-layout {
display: grid;
grid-template-columns: 250px 1fr;
gap: 2rem;
}
/* Full-width container with fixed gutters */
.container {
width: calc(100% - 3rem);
max-width: 1200px;
margin-inline: auto;
}
/* Fluid typography alternative */
h1 {
font-size: calc(1.5rem + 2vw);
}
/* Height minus header */
.content {
min-height: calc(100dvh - 4rem);
}
/* Background that extends beyond content area */
.hero {
width: 100vw;
margin-left: calc(-50vw + 50%);
}Unit Comparison Table
A quick comparison of how different units behave at different scales. Assumes root font size of 16px and a 1200px wide viewport.
| Value | px | rem | em (parent 16px) | vw (1200px) | % |
|---|---|---|---|---|---|
| Small | 8px | 0.5rem | 0.5em | 0.67vw | 0.67% |
| Body | 16px | 1rem | 1em | 1.33vw | 1.33% |
| Medium | 24px | 1.5rem | 1.5em | 2vw | 2% |
| Large | 32px | 2rem | 2em | 2.67vw | 2.67% |
| Heading | 48px | 3rem | 3em | 4vw | 4% |
🎯 Summary: Unit Decision Flow
- font-size →
rem(orclamp()for fluid scaling) - spacing (padding, margin, gap) →
rem(consistent everywhere) - widths →
%(fluid),rem(fixed content),min()(max bound) - heights →
auto(preferred),dvh(full-screen) - borders / shadows →
px(keep them crisp) - icon sizes →
em(scale with text) - line-height → unitless number (always)
- fluid typography →
clamp()withremandvw - full viewport sections →
100dvh(dynamic) or100svh(small) - mixed calculations →
calc()
Common Mistakes & How to Avoid Them
CSS units seem simple until a layout breaks. These are the mistakes developers make most often — and the fixes that prevent them.
1. Using px for Font Sizes Hurts Accessibility
pxfont sizes ignore the user's browser font-size setting, so users who increase their default font size (often for vision reasons) see no change on your site. Use rem for font sizes — it scales with the root font size — and reserve px for borders, shadows, and 1px hairline rules that should stay crisp.
2. Confusing em with rem
rem is always relative to the root element font size (usually 16px), so it is predictable anywhere in the tree. em is relative to the currentelement's font size, and because it compounds, nested elements can produce surprising sizes: a 1.5em padding inside a 1.5em font becomes 2.25em of effective spacing. Use rem for global spacing and typography; use em deliberately when a component should scale with its own font size (icons, button padding).
3. Using 100vh for Mobile Full-Height Sections
On mobile browsers, 100vh refers to the largest viewport, which includes the area hidden behind the URL bar — so a 100vh section gets cut off or causes scroll jumps when the bar collapses. Use 100dvh (dynamic viewport height) for mobile full-height layouts, with 100svh as a fallback for older browsers.
4. Using vw for Font Sizes Without clamp()
A headline set to 4vw looks great on desktop but becomes unreadably small on phones and comically huge on ultrawide monitors. Wrap viewport units in clamp() with rem bounds: font-size: clamp(1.5rem, 4vw, 3rem). This gives you fluid scaling without ever crossing accessibility limits.
5. Expecting Percentage Heights to "Just Work"
height: 50% only works when the parent has an explicit height (not auto). A common trap is setting a child to 100% inside a parent whose height comes from content — the percentage resolves to autoand the layout collapses. If the parent's height is content-driven, use flexbox/grid stretch, min-height, or viewport units instead of percentages.
Frequently Asked Questions
What is the difference between px and rem?
px is an absolute unit — 1px is 1/96th of an inch on screen — so it never changes regardless of browser settings. rem is relative to the root element font size (usually 16px, so 1rem = 16px). Because remscales when users change their browser's default font size, it is the recommended unit for font sizes, padding, and margin. Use px for borders and shadows that must stay visually identical at any zoom level.What is the difference between em and rem?
rem is relative to the root element font size, so 1rem is the same everywhere in the document. em is relative to the current element's font size, and it compounds through nesting — a 2em margin inside a 1.5em font resolves to 3em. This makes em great for components that should scale with their own text (icon sizes, button padding) and rem better for site-wide spacing and typography.When should I use vw and vh?
vw and vh are 1% of the viewport width and height. Use them for full-screen hero sections, overlays, and fluid typography inside clamp(). Avoid raw vh for mobile heights — the URL bar changes the visible viewport, so use 100dvh (dynamic) or 100svh (small) instead. For widths, prefer % when the size should relate to a container rather than the whole viewport.Should I use px or rem for font sizes?
rem. Because rem is relative to the root font size, it respects the user's browser font-size preference — a core accessibility requirement. px ignores that setting, which can make your text impossible to resize for users with low vision. A common pattern is setting the root font size in rem (or leaving it at the default 16px) and sizing everything else in rem, with clamp() for fluid type.What is the difference between vh, svh, lvh, and dvh?
vh equals 1% of the largest viewport — on mobile that includes the area hidden behind the browser UI. svh is the small viewport (visible area when the URL bar is shown), lvh is the large viewport (URL bar hidden), and dvh is the dynamic viewport, which updates live as the browser UI expands and collapses. For mobile full-height sections, 100dvh gives the smoothest behavior, with 100svh as a fallback.Related Tools: JSON Formatter · Base64 Encoder/Decoder · Regex Tester