Both units are based on font size, so layouts built from them grow with the text. They differ in what they measure against.
rem: the root
1rem equals the font size of the root element, html. Browsers set it to 16px by default, so 1.5rem is 24px everywhere on the page, no matter how deeply an element is nested.
em: the current element (or its parent)
- For
font-size,1emis the parent’s font size. - For everything else (
padding,margin,width),1emis the element’s own font size.
<style>
html { font-size: 16px; }
.rem { font-size: 1.5rem; }
.rem .inner { font-size: 1.5rem; }
.em { font-size: 1.5em; }
.em .inner { font-size: 1.5em; }
</style>
<p class="rem">rem: 24px <span class="inner">still 24px</span></p>
<p class="em">em: 24px <span class="inner">now 36px (1.5 × 24)</span></p>
The em example compounds: the inner 1.5em multiplies the already enlarged parent. That is the usual cause of “my nested lists get bigger and bigger”.
When em is useful
Because padding: 0.75em 1.5em follows the element’s own font size, a button’s padding automatically grows when you make its text larger.
.btn { font-size: 1rem; padding: 0.6em 1.2em; }
.btn-large { font-size: 1.25rem; } /* padding scales along with it */
A simple recommendation
- Font sizes:
rem. - Padding and margin:
remfor layout spacing,eminside components that scale with their text. - Media queries:
emis the most reliable unit, as it follows the visitor’s font size settings. Pixel breakpoints are fine too.
Counting from 16px
0.5rem is 8px, 0.75rem is 12px, 1.25rem is 20px and 2rem is 32px. Keep the 16px base in mind and the numbers become easy to estimate.