How to set font sizes in CSS

6th May, 2020

There are lots of ways to set the size of text in CSS. px, em and rem are the most popular options, but what’s the difference between them?

Pixels (px)

Pixels are an absolute unit of measurement in CSS. That means that if a user writes font-size: 16px the output will be text at 16px.

Pixels are an easy option, but they create accessibility issues. Users who need to increase the browser’s default font size won’t be able to when the font size is set as pixels.

Ems (em)

em is a relative unit of measurement. That means its size is relative to something else, but what?

em units are relative to their parent element. 1em is the same as the current parent’s font size.

If the parent element’s font size is 16px, 1em would be 16px. That seems simple, but how does it work in practice?

If you had the following CSS:

body {
	font-size: 16px;
}
p {
	font-size: 1.5em;
}

And this HTML:

<body>
	<p>What size will this text be?</p>
</body>

The p text would be calculated as 1.5em x 16px = 24px. The parent of p is body so the value of em (1.5) is multiplied by 16px.

You can see that in this Codepen – experiment with some different values, too.

See the Pen (@websmyth) on CodePen.

Root font size

To make these examples easier to understand, they all use a pixel value for the body font size:

body {
	font-size: 16px;
}

It’s often better not to set a root font size. If we have to, set it at the html level as a relative unit:

html {
	font-size: 100%;
}

Ems and nesting

This works well as the text will scale up and down if a user changes the default font size, but it can be confusing. What happens if there are several nested elements?

If our HTML looked like this:

<body>
	<article>
    	<p>What size will this text be?</p>
    </article>
</body>

And had the following CSS:

body {
	font-size: 16px;
}
article {
	font-size: 1.5em;
}
p {
	font-size: 2em;
}

How is the p font size calculated? Here’s what happens:

The article font size is calculated as 1.5em x 16px (the font size of its parent, body). That gives article a font size of 24px.

The p font size is calculated based on its parent font size. Its parent is article, so 2em x 24px = 48px.

You can see that in action here:

See the Pen (@websmyth) on CodePen.

Rems (rem)

This is where the rem unit comes in handy. rem units work in exactly the same way as em units, except for one key difference:

The calculation is based on the root element, not the parent. That’s what the r stands for.

Returning to our example from above, the final font size of p would now be 32px because the calculation is now 2rem x 16px (the value set at the root, which is html).

See the Pen (@websmyth) on CodePen.

The rem unit allows font sizing to scale but it’s also predictable. You no longer have to worry about the impact of parent element sizes, so they’re the best of both worlds.