Difficulty: Beginner
What are the different CSS units? When should you use each?
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
/* 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.
/* 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.
/* 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.
CSS Units, rem, em, Viewport Units, Percentage, Responsive Typography