CSS Units
Understand the difference between absolute and relative CSS units, and know when to use px, %, em, rem, viewport units, ch, and fr.
Every length in CSS — a width, a font-size, a margin — needs a unit, and CSS offers far more than just pixels. Choosing the right unit is what separates a layout that scales gracefully across devices and user preferences from one that breaks the moment someone changes their browser's font size or resizes the window.
Absolute vs. relative units
Absolute units always represent the same physical measurement regardless of context — px is the main one used in web design (technically defined relative to a reference pixel, but treated as a fixed unit in practice). Relative units scale based on something else: the parent's font size, the root font size, the viewport size, or another element's dimensions. Relative units are what make responsive, accessible layouts possible.
px — pixels
px is the most literal, predictable unit — it doesn't scale with anything else by default. It's useful for things that genuinely shouldn't change size (like a 1px border), but overusing px for font sizes and spacing makes layouts brittle and can ignore a user's accessibility font-size preferences in some browsers.
% — percentage
Percentage values are relative to a reference set by the property itself — most commonly the parent element's corresponding dimension. width: 50% means half the parent's width. For font-size, percentage is relative to the parent's computed font-size.
em — relative to the element's own font size
1em equals the current font-size of the element it's used on (or, when used for font-size itself, the parent's font-size). This makes em compounding: if a parent has font-size: 20px and a child has font-size: 1.5em, the child is 30px — but if that child contains another nested element also set in em, it compounds again relative to the child's new 30px. This nesting behavior is powerful for things like padding that should scale with an element's own text size, but can cause unexpected growth in deeply nested components.
rem — relative to the root font size
1rem always equals the font-size of the root <html> element (typically 16px by default, unless changed), no matter how deeply nested the element is. This avoids the compounding problem em has — every rem value in your whole stylesheet scales consistently from one single source of truth. Because of this, rem is generally the preferred unit for font-size, margin, padding, and most spacing in modern CSS — it gives predictable, consistent scaling, and respects a user's browser-level font size preference (since it's ultimately tied to the root font-size, which browsers let users adjust).
Viewport units: vw, vh, vmin, vmax
These are relative to the browser's viewport (visible window) size: 1vw = 1% of viewport width, 1vh = 1% of viewport height. vmin takes the smaller of the two (useful for things that must fit regardless of orientation), vmax takes the larger. They're commonly used for full-screen hero sections (height: 100vh) or text that scales with screen size.
ch, ex, and fr
ch is relative to the width of the '0' (zero) character in the current font — extremely useful for setting a readable maximum line length for text, e.g. max-width: 65ch approximates a comfortable reading measure regardless of font. ex is relative to the x-height of the font (the height of a lowercase 'x') — rarely used in practice. fr (fraction unit) is exclusive to CSS Grid — it distributes available space in a grid container proportionally, e.g. grid-template-columns: 1fr 2fr gives the second column twice the space of the first, after fixed-size tracks are subtracted.
Common unit usage
fr only works inside grid-template-columns / grid-template-rows. 1rem is always relative to <html>'s font-size, never to any other ancestor.
/* Absolute */
border: 1px solid #ccc;
/* Relative to parent (%) */
.container { width: 90%; }
/* Relative to element's own font-size (em) — compounds when nested */
.badge { padding: 0.5em 1em; }
/* Relative to root font-size (rem) — does NOT compound */
html { font-size: 16px; }
h1 { font-size: 2.5rem; } /* 40px, regardless of nesting depth */
p { margin-bottom: 1rem; } /* 16px */
/* Viewport units */
.hero { height: 100vh; }
.title { font-size: 5vw; }
/* Reading-length text */
article { max-width: 65ch; }
/* Grid fraction unit */
.grid {
display: grid;
grid-template-columns: 200px 1fr 2fr;
}Code Examples
Each nested em compounds on the previous computed size — after a few levels of nesting this produces unexpectedly large or small text, which is one of the main reasons rem is preferred for most sizing.
No matter how deeply nested, 1.2rem always computes the same way because it only ever looks at the root element's font-size, never a parent's.
A realistic pattern: rem for consistent, scalable spacing and typography; fr for proportional grid columns that adapt to the container's available width.
.level-1 { font-size: 1.2em; } /* 1.2 x parent (e.g. 16px) = 19.2px */
.level-1 .level-2 { font-size: 1.2em; } /* 1.2 x 19.2px = 23px */
.level-1 .level-2 .level-3 { font-size: 1.2em; } /* 1.2 x 23px = 27.6px, and so on */html { font-size: 16px; }
.level-1 { font-size: 1.2rem; } /* 19.2px */
.level-1 .level-2 { font-size: 1.2rem; } /* still 19.2px — always relative to html */
.level-1 .level-2 .level-3 { font-size: 1.2rem; } /* still 19.2px */.card {
display: grid;
grid-template-columns: 1fr 3fr;
gap: 1rem;
padding: 1.5rem;
}
.card h3 {
font-size: 1.25rem;
line-height: 1.4;
}em vs. rem relative to what
em compounds through each nested level; rem always refers back to the html root, flat.
<html style="font-size:16px"> <-- rem always measures from HERE
<div style="font-size:1.2em"> (=19.2px; em measures from ITS parent)
<p style="font-size:1.2em"> (=23.04px; compounds again)
<span style="font-size:1.2rem"> (=19.2px; rem ignores nesting, uses html)
</span>
</p>
</div>
</html>Important Rules
px is absolute and predictable, but doesn't scale with user or parent context.
% is relative to a parent dimension (which one depends on the property).
em is relative to the current element's own font-size (or the parent's, when sizing font-size itself), and compounds when nested.
rem is relative only to the root <html> font-size — it never compounds, making it the safer default for most spacing and typography.
vw/vh/vmin/vmax are relative to the viewport's width/height/smaller-dimension/larger-dimension.
ch approximates character width, useful for readable line lengths; fr is exclusive to CSS Grid track sizing.
The rem-first convention
Most modern CSS style guides and frameworks default to rem for font-size, margin, padding, and gap, reserving px only for things that must stay visually fixed regardless of zoom or accessibility settings — like 1px hairline borders or icon dimensions in some cases. This convention respects users who increase their browser's default font size for readability..card.card-inner.card-title { font-size: 1.1em; } /* deeply nested em */.card-title { font-size: 1.1rem; } /* flat, predictable */
Using em for font-size inside deeply nested components causes compounding that's hard to predict or debug. rem keeps every element's size traceable to one root value..hero { height: 100vh; } /* on mobile, can cause content to be cut off behind browser UI */.hero { min-height: 100vh; } /* or use the newer 100dvh where supported */
A fixed height: 100vh doesn't account for mobile browsers' address bar showing/hiding, which changes the visible viewport. min-height is more forgiving, and newer dynamic viewport units (dvh) solve this more precisely.
[True / False] True or False: Using em for font-size on deeply nested elements is generally safer than rem because em always measures from the html root element, avoiding compounding. A. True B. False
B. False — False — this has it backwards. em measures relative to the immediate parent's font-size and compounds with each nested level; rem is the one that always measures from the html root and does not compound. rem is generally the safer, more predictable choice for nested typography.
The root font-size is the default 16px. Convert the following px values to rem: 32px, 8px, 20px. Then explain in one sentence why rem is generally safer than px for these values.
32px = 2rem, 8px = 0.5rem, 20px = 1.25rem. rem is generally safer because it scales proportionally if a user changes their browser's base font size for accessibility, while px values stay visually fixed regardless of that preference.
Divide each px value by 16.