CSS Units Explained:
px, rem, em, %, vw & vh

One of the most common sources of confusion in CSS — finally explained in plain English. Know exactly which unit to use and why.

Every developer has been there — staring at a layout wondering: should I use px or rem here? What about em? Or %? Picking the wrong unit causes broken layouts, poor accessibility, and headaches during responsive design. This guide explains every major CSS unit clearly, with real-world examples, so you never second-guess yourself again.

A Quick Overview: Absolute vs Relative Units

CSS units fall into two families:

  • Absolute units — Fixed size, never change regardless of screen or user settings. Example: px, pt, cm.
  • Relative units — Scale based on something else (parent element, root font size, viewport). Example: rem, em, %, vw, vh.
UnitTypeRelative ToBest Used For
pxAbsoluteDevice pixels (CSS pixels)Borders, box shadows, precise icons
remRelativeRoot <html> font sizeFont sizes, spacing, layout padding
emRelativeParent element's font sizeComponent-level spacing, buttons
%RelativeParent element's dimensionFluid widths, images, containers
vwRelative1% of viewport widthFull-width sections, hero text
vhRelative1% of viewport heightFull-screen sections, modals
vminRelativeSmaller of vw or vhSquare elements, responsive icons
vmaxRelativeLarger of vw or vhFull-bleed backgrounds
chRelativeWidth of "0" characterReadable text column widths
clamp()FunctionCombines min, preferred, maxFluid typography & spacing

1. px — Pixels (The Absolute Unit)

A CSS pixel (px) is the most familiar unit. It maps to a logical pixel on screen — not a physical device pixel (retina screens may use 2–3 physical pixels per CSS pixel). It is fixed and does not change with user browser zoom preferences in the same accessible way relative units do.

/* ✅ Good uses of px */
border: 1px solid rgba(255,255,255,0.1);
box-shadow: 0 4px 24px rgba(0,0,0,0.3);
border-radius: 8px;

/* ❌ Avoid px for font-size — it ignores browser zoom */
font-size: 16px; /* user can't scale this with browser settings */
⚠️ Accessibility Warning: Using px for font sizes overrides a user's browser text-size preference, which can make your site inaccessible for people with visual impairments. Always use rem for font sizes.

2. rem — Root Em (The Modern Standard)

rem stands for Root Em. It is always relative to the font-size set on the <html> element. By default, browsers set html { font-size: 16px; }, so 1rem = 16px.

The beauty of rem is that if a user increases their browser's default font size (for accessibility), everything sized in rem scales proportionally.

/* Default: html font-size is 16px */
html { font-size: 16px; }

/* So these are equivalent: */
font-size: 1rem;    /* = 16px */
font-size: 1.5rem;  /* = 24px */
font-size: 0.875rem;/* = 14px */

/* A useful trick — set base to 62.5% for easy math */
html { font-size: 62.5%; } /* 1rem = 10px */
font-size: 1.6rem;  /* = 16px — easy! */
💡 Pro Tip: Use rem for font sizes, padding, margin, and gap. It keeps your entire spacing system proportional and accessible across all devices and user preferences.

3. em — Em (Context-Aware Relative Unit)

em is relative to the font-size of its own parent element, not the root. This makes it powerful for component-level scaling — but also dangerous because it compounds (inherits and multiplies) when nested.

/* Parent has font-size: 20px */
.parent { font-size: 20px; }

/* Child: 1em = 20px (inherited from parent) */
.child { font-size: 1em; }   /* = 20px */
.child { font-size: 0.8em; } /* = 16px */

/* ⚠️ Compounding problem with nested ems */
.grandchild { font-size: 0.8em; } /* = 0.8×16 = 12.8px — unintended! */

When to use em: It shines for padding and margin inside a component, where you want spacing to scale with the component's own font size. For example, a button's padding defined in em will naturally grow when the button's text is larger.

/* Button padding scales with its own font-size */
.btn {
  font-size: 1rem;
  padding: 0.75em 1.5em; /* relative to button's own font */
}
.btn-lg {
  font-size: 1.25rem;
  /* padding auto-scales — no extra CSS needed! */
}

4. % — Percentage

Percentages are relative to the parent element's size. They are the foundation of fluid, responsive layouts — especially for widths and heights.

/* Fluid image — always fills its container */
img { width: 100%; height: auto; }

/* Two-column layout */
.col { width: 50%; }

/* Note: padding/margin % is relative to parent WIDTH, not height */
.aspect-box {
  width: 100%;
  padding-top: 56.25%; /* 16:9 aspect ratio trick */
}

5. vw & vh — Viewport Units

vw (viewport width) and vh (viewport height) are each 1% of the browser window's dimensions. They are perfect for full-screen layouts.

/* Full-screen hero section */
.hero {
  width: 100vw;
  height: 100vh;
}

/* Fluid typography that scales with screen width */
h1 { font-size: 5vw; }

/* Better: use clamp() to set min and max */
h1 { font-size: clamp(2rem, 5vw, 4rem); }
⚠️ Mobile vh Bug: On mobile browsers, 100vh includes the browser toolbar height, causing content to be cut off. Use min-height: 100svh (small viewport height) for mobile-safe full-screen sections. It is now supported in all modern browsers.

6. vmin & vmax

vmin is 1% of the smaller of vw or vh. vmax is 1% of the larger. These are great for responsive square elements or typography that should adapt to any orientation.

/* Square element that fits any screen orientation */
.avatar {
  width: 20vmin;
  height: 20vmin;
}

7. ch — Character Width

1ch equals the width of the "0" character in the current font. It is the perfect unit for setting readable line lengths. Typographers recommend 60–75 characters per line for optimal readability.

/* Optimal readable text column */
.article-body {
  max-width: 68ch;
  margin: 0 auto;
}

8. clamp() — The Modern Fluid Unit

clamp(min, preferred, max) is not a unit itself, but a CSS function that combines three values. It is the cleanest way to write fluid, responsive typography and spacing with zero media queries.

/* Font size: min 1rem, scales with viewport, max 3rem */
h1 { font-size: clamp(1.75rem, 4vw + 1rem, 3.5rem); }

/* Padding: min 1rem, scales, max 4rem */
.section { padding: clamp(1rem, 5vw, 4rem); }

/* Container width */
.container { width: clamp(320px, 90%, 1200px); }
💡 Pro Tip: clamp() is the future of responsive design. Combine it with rem for font sizes and vw for the fluid middle value to create layouts that are perfectly readable on every screen — no breakpoints required.

When to Use Which Unit — The Cheat Sheet

PropertyRecommended UnitWhy
Font size (global)remRespects browser accessibility settings
Font size (component)em or remUse em for component self-scaling
Padding & marginremConsistent spacing system
Button paddingemScales with button's font size
Layout widths% or chFluid, fills parent container
Borders, shadowspxAlways crisp, no scaling needed
Full-screen sections100vh / 100svhFill viewport, use svh on mobile
Fluid typographyclamp(rem, vw, rem)Scales smoothly without breakpoints
Readable text columnchTypographically correct line length
Responsive icons/squaresvminAdapts to screen orientation

Real-World Example: A Fully Responsive Card

.card {
  width: clamp(280px, 90%, 480px);   /* fluid width */
  padding: 2rem;                      /* consistent spacing */
  border-radius: 16px;               /* fixed rounding */
  border: 1px solid rgba(255,255,255,0.1); /* crisp border */
}

.card h2 {
  font-size: clamp(1.25rem, 2.5vw, 1.75rem); /* fluid heading */
  margin-bottom: 0.75rem;
}

.card p {
  font-size: 1rem;
  max-width: 55ch;                    /* readable line length */
  line-height: 1.7;
}

.card .btn {
  font-size: 1rem;
  padding: 0.75em 1.5em;             /* scales with btn font */
  margin-top: 1.5rem;
}

Common Mistakes to Avoid

  • Using px for font sizes — Always use rem to preserve browser accessibility settings.
  • Nesting em deeply — Compounding effect causes unpredictable sizes. Prefer rem for global spacing.
  • Using 100vh on mobile — The toolbar overlay causes overflow. Use 100svh or a JS-based fallback.
  • Setting widths in px — Use %, rem, or clamp() for fluid, responsive containers.
  • Ignoring clamp() — It replaces dozens of breakpoint-based media query rules with a single line.

Final Thoughts

Choosing the right CSS unit is not just a technical decision — it directly impacts your site's accessibility, responsiveness, and maintainability. The golden rules are simple: use rem for typography and global spacing, em for component-level scaling, % for fluid containers, px for precise decorative details, and clamp() whenever you want fluid, breakpoint-free scaling.

Master these units and your CSS will be cleaner, more readable, and work beautifully on every screen — from a 320px mobile to a 4K monitor.

Want a website built with pixel-perfect, accessible CSS from day one? Get a free quote from Pixel Precision Web today.

Share this article: Twitter / X Facebook LinkedIn WhatsApp