px vs rem vs em
Table of Contents + −
In the last lesson you learned about CSS Units. Now let’s look closely at the three units you will use the most for sizing text and spacing. They are px, rem, and em. People mix these up all the time. So let’s make them simple.
🤔 Why Do We Even Need Different Units?
You might think one unit is enough. Just pick a size and move on, right? But here is the real problem.
Say you build a website with all the text at a fixed size. Then someone opens it who finds small text hard to read. They go into their browser settings and make the default text bigger. Your fixed text does not change at all. It stays tiny for them. That is a real accessibility problem. “Accessibility” means making your site usable for everyone, including people who need bigger text.
So we use different units for different jobs:
- Some units stay exactly the same no matter what. These are good when you want full control.
- Some units grow and shrink based on a setting. These are good when you want the page to respect the user.
The unit you pick decides whether your design adapts to the user or ignores them. “Adapts” just means it changes to fit the situation.
📏 px — The Fixed Unit
px means pixel. A pixel is one tiny dot on the screen. When you say 16px, you mean “make this exactly 16 dots tall”. It does not care about any setting. It is fixed.
Think of px like a ruler made of metal. The marks never move. 16 is always 16.
Here is text set with a fixed pixel size.
p { font-size: 16px;}This says every paragraph is exactly 16 pixels tall. Simple and easy to predict.
What you see
The paragraph text is a normal readable size. But if a user changes their browser’s default font size to make text bigger, this text does not grow. It stays at 16 pixels.
The good part of px is control. You always know the exact size. The bad part is it ignores the user’s own text-size setting. So px is great for things like borders, where you really do want a thin fixed line.
A 1 pixel border looks sharp and the same everywhere.
.card { border: 1px solid gray;}🌳 rem — Based on the Root
Now let’s fix that accessibility problem. This is where rem comes in.
rem means “root em”. The “root” is the <html> element. That is the top element, the parent of everything on the page. The rem unit is measured against the font size of that root element.
By default, the root font size in most browsers is 16px. So 1rem equals 16px. And 2rem equals 32px. Easy.
Think of rem like a class of students following one teacher. The teacher sets one size. Everyone measures from the teacher. If the teacher changes the size, the whole class follows.
Here we set a heading and a paragraph using rem.
h1 { font-size: 2rem; /* 2 × 16 = 32px */}
p { font-size: 1rem; /* 1 × 16 = 16px */}Here is the nice part. If a user sets their browser default to 20px instead of 16px, then 1rem now becomes 20px. Your whole page scales up with them. You did not write any extra code. It just respects their choice.
What you see
On a normal setup the heading is 32px and the paragraph is 16px. If the user makes their browser text larger, both grow together and keep the same look. Nothing breaks.
The strength of rem is that everything stays linked to one root size. Change the root once, and your whole page scales. This is why most people use rem for font sizes today.
👨👦 em — Based on the Parent
em is the tricky one. It looks like rem, but it measures differently.
em is measured against the font size of its own parent element, not the root. The “parent” is the element that wraps it. So the answer depends on where the element sits.
Think of em like a child copying their own parent’s height, not the teacher’s. Different families, different sizes.
Let’s see why this surprises people. Here a box has a font size, and a button inside it uses em for padding.
.box { font-size: 20px;}
.box button { padding: 1em; /* 1 × 20 = 20px, because the parent is 20px */}The button’s 1em padding becomes 20px, because its parent .box is 20px. If the parent were 30px, that same 1em would become 30px. The value moves with the parent.
This causes a famous trap called compounding. “Compounding” means the effect stacks up and multiplies at each level. If you nest em font sizes inside each other, they keep multiplying. Then the text grows out of control.
Here is the trap. Each list level uses 1.5em, so the text gets bigger and bigger as you go deeper.
ul { font-size: 1.5em;}<ul> <li>Level one <ul> <li>Level two <ul> <li>Level three</li> </ul> </li> </ul> </li></ul>What you see
Level one text is bigger than normal. Level two is bigger again. Level three is huge. Each level multiplied the size of the one above it. That is compounding, and it is usually not what you wanted.
So em is useful when you actually want a size to follow its parent. A good example is padding inside a button that should grow with the button’s own text. But for plain font sizes, it can cause surprises.
📊 px vs rem vs em Side by Side
Here is a quick way to remember the difference between the three.
| Unit | Measured against | Best for |
| px | Nothing. It is fixed. | Borders and exact fixed sizes |
| rem | The root html font size | Font sizes and most spacing |
| em | The parent element’s font size | Padding or spacing that should follow its own text |
⚠️ Common Mistakes
These are the slip-ups beginners hit most with these units.
- Using
pxfor every font size. It works, but it ignores users who need bigger text. Preferremfor fonts. - Nesting
emfont sizes without thinking. The sizes compound and your text gets way too big. Switch toremif you do not want that. - Thinking
remandemare the same. They are not.remlooks at the root.emlooks at the parent. - Forgetting that the default root size is usually
16px. That is why1remis16pxuntil you change it.
✅ Best Practices
Here is a simple plan you can follow every time.
- Use
remfor font sizes. Your text then respects the user’s browser setting. - Use
pxfor things that truly must be fixed, like a thin1pxborder. - Use
emonly when you want a value to grow with its own element’s text, like button padding. - Keep your root font size simple. Leave it near
16pxso1remis easy to picture.
Quick mental check
Ask yourself one question. “Should this size follow the user, follow the parent, or stay fixed?” Follow the user means rem. Follow the parent means em. Stay fixed means px.
🧩 What You’ve Learned
Let’s go over the main points one more time.
- ✅
pxis a fixed unit. It is one dot on the screen and never changes with settings. - ✅
remis measured against the roothtmlfont size, which is usually16px. - ✅
emis measured against the parent element’s font size, not the root. - ✅
emcan compound when nested, so the text keeps multiplying in size. - ✅ Use
remfor fonts,pxfor fixed borders, andemwhen you want to follow the parent.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does 1rem equal when the root font size is the usual 16px?
Why: rem is measured against the root font size. With a 16px root, 1rem is 16px.
- 2
Which unit is measured against the parent element's font size?
Why: em looks at its own parent's font size. rem looks at the root, and px is fixed.
- 3
Why is rem often the best choice for font sizes?
Why: rem scales with the root. So when a user makes their browser text bigger, your rem-based text grows with it.
- 4
What problem can happen when you nest em font sizes inside each other?
Why: Each nested em multiplies on top of the one above it. This compounding makes the text grow larger at each level.
🚀 What’s Next?
Now that you can size things the smart way, let’s move on to styling the actual look of your text.