CSS Units (rem, em, vw, vh, %)

Difficulty: Beginner

Question

What are the different CSS units? When should you use each?

Answer

CSS units fall into two categories: absolute and relative.

Absolute: px (pixels) - fixed, doesn't scale

Relative: - rem: relative to root font-size (html element, default 16px) - em: relative to parent's font-size - %: relative to parent's dimension - vw/vh: 1% of viewport width/height - vmin/vmax: 1% of smaller/larger viewport dimension - ch: width of '0' character - dvh: dynamic viewport height (accounts for mobile browser chrome)

Best practices: - rem for font-size (respects user preferences) - rem or px for spacing/padding - % or vw for widths - vh or dvh for full-screen sections

Code examples

rem vs em

/* rem: relative to ROOT (html) font-size */
html { font-size: 16px; } /* browser default */

h1 { font-size: 2rem; }     /* 32px */
p  { font-size: 1rem; }     /* 16px */
.small { font-size: 0.875rem; } /* 14px */

/* em: relative to PARENT font-size */
.parent { font-size: 20px; }
.child  { font-size: 1.5em; }  /* 30px */
.grandchild { font-size: 1.5em; } /* 45px! compounding */

/* em for component-relative spacing */
.button {
  font-size: 1rem;
  padding: 0.5em 1em;
  /* Padding scales with font-size */
  /* If font-size changes, padding adjusts */
}
.button--lg {
  font-size: 1.25rem;
  /* Padding automatically larger: 0.625rem 1.25rem */
}

/* Why rem > em for font-size: no compounding */

rem is predictable because it always references the root. em compounds (each nested level multiplies), which can cause unexpected sizes.

Viewport Units

/* vw/vh: percentage of viewport */
.hero {
  height: 100vh;  /* full viewport height */
  width: 100vw;   /* full viewport width */
}

/* Problem: 100vh on mobile includes hidden browser chrome */
/* Solution: dvh (dynamic viewport height) */
.hero-mobile-safe {
  height: 100dvh; /* adjusts when address bar shows/hides */
}
/* svh: smallest possible viewport */
/* lvh: largest possible viewport */

/* Fluid typography with vw */
h1 {
  font-size: 5vw;
  /* Problem: too small on mobile, too big on desktop */
}

/* Better: clamp() */
h1 {
  font-size: clamp(1.5rem, 4vw, 3.5rem);
  /* min: 1.5rem, preferred: 4vw, max: 3.5rem */
}

/* vmin/vmax for square elements */
.square {
  width: 50vmin;
  height: 50vmin;
  /* Always square, sized to smaller dimension */
}

dvh solves the notorious mobile 100vh bug where content hides behind the browser chrome. clamp() is the modern way to do fluid typography.

When to Use Each Unit

/* FONT SIZE: use rem */
body { font-size: 1rem; }      /* 16px default */
h1   { font-size: 2.25rem; }   /* 36px */

/* SPACING/PADDING: use rem or px */
.section { padding: 4rem 2rem; }
.card { padding: 1.5rem; }
.gap { gap: 1rem; }

/* WIDTH: use %, max-width with px/rem */
.container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

/* HEIGHT: use vh/dvh for sections */
.hero { min-height: 100dvh; }

/* BORDERS/SHADOWS: use px (don't need to scale) */
.card {
  border: 1px solid #e5e7eb;
  box-shadow: 0 4px 6px rgb(0 0 0 / 0.1);
}

/* MEDIA QUERIES: use em (best cross-browser) */
@media (min-width: 48em) { /* 768px */ }
@media (min-width: 64em) { /* 1024px */ }

rem for font sizes respects user zoom settings. px for things that shouldn't scale (borders, shadows). em in media queries has the best cross-browser support.

Key points

Concepts covered

CSS Units, rem, em, Viewport Units, Percentage, Responsive Typography