Relative Units (em, rem, %)
Relative units scale in relation to something else — a parent's font size, the root font size, or the container's dimensions. They're the key to building layouts and typography that adapt to different screen sizes, user preferences, and content contexts. The three most important are em, rem, and % — each useful for different purposes.
em — relative to the current font size
1em equals the computed font size of the current element. If the element's font size is 18px, 1em is 18px, 0.5em is 9px, and 2em is 36px. For properties other than font-size, em is relative to the element's own font-size. For font-size itself, em is relative to the parent's font-size.
/* em for font-size — relative to parent's font-size */
body { font-size: 16px; }
p { font-size: 1em; } /* 16px — same as parent */
small { font-size: 0.875em; } /* 14px — 87.5% of 16px */
h1 { font-size: 2em; } /* 32px — twice the parent */
/* em for spacing — relative to the element's OWN font-size */
.heading {
font-size: 2rem; /* 32px */
margin-bottom: 0.5em; /* 16px — 0.5 × 32px (not 0.5 × root) */
padding-inline: 1em; /* 32px — proportional to the heading's own size */
}
/* This means em-based spacing scales with font-size automatically */rem — relative to the root font size
1rem always equals the root element's (<html>) font size, regardless of where the element is nested. It doesn't compound. This makes it ideal for font sizes and consistent spacing:
/* The root font size — typically 16px browser default */
:root { font-size: 16px; } /* or leave it alone and use the browser default */
/* rem values — always relative to :root */
h1 { font-size: 2rem; } /* 32px — always */
h2 { font-size: 1.5rem; } /* 24px — always */
h3 { font-size: 1.25rem; } /* 20px — always */
p { font-size: 1rem; } /* 16px — always */
/* Spacing scale in rem — consistent across the site */
:root {
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-12: 3rem; /* 48px */
}
/* rem respects user font size preferences */
/* If user sets browser font size to 20px: */
h1 { font-size: 2rem; } /* → 40px — scales correctly */% — relative to the parent or context
Percentage values are relative to the parent's value for the same property — for most properties. There are notable exceptions:
/* Width — % of parent's width */
.column { width: 50%; } /* half the parent's width */
/* Height — % of parent's HEIGHT (requires parent to have a definite height) */
.full-height { height: 100%; } /* needs parent to have a height set */
/* Font-size — % of parent's font-size (same as em) */
p { font-size: 90%; } /* 90% of parent's font-size */
/* Margin and padding — ALWAYS % of parent's WIDTH (even for top/bottom!) */
.card { padding: 5%; } /* 5% of parent's width — all four sides */
/* Line-height — % of element's own font-size */
p { line-height: 160%; } /* 160% of the element's font-size */
/* Transform translate — % of the element's own dimensions */
.center {
transform: translate(-50%, -50%); /* moves left by 50% of own width, up by 50% of own height */
}Choosing between em, rem, and %
Use case | Recommended unit | Why |
|---|---|---|
Font sizes |
| Doesn't compound; respects user preferences |
Component padding/margin |
| Scales with the component's font size |
Global spacing tokens |
| Consistent across the whole page |
Layout widths |
| Relative to container or screen |
Border radius |
| Fixed (px) or percentage of element size (%) |
Line height | Unitless ( | Avoids computed-value inheritance issue |
Media query breakpoints |
|
|
/* A well-structured approach combining all three */
:root {
font-size: 100%; /* respect browser default (typically 16px) */
}
body {
font-size: 1rem; /* 16px — uses root/browser preference */
line-height: 1.6; /* unitless */
}
h1 {
font-size: 2.25rem; /* always 36px relative to root */
margin-bottom: 0.5em; /* 18px — scales if h1 font-size changes */
}
.container {
max-width: 75rem; /* 1200px — in rem, scales with user preferences */
padding-inline: 1.5rem; /* 24px base padding */
margin-inline: auto;
}
.card {
padding: 1.5rem; /* consistent with spacing scale */
border-radius: 0.5rem; /* 8px */
}