What's the difference between em, rem and px in CSS?

Units of measurement for sizing in CSS can be confusing. With an increased focus on responsive design (making the same site adapt to different devices/screen sizes) over the past few years, it's often no longer enough to just define sizes for everything in pixels.

Pixels are an absolute unit of measurement. That means they won't change size depending on the value of their parent element, or anything else on your page. em and rem units are relative, meaning they have no fixed size, but instead are sized relative to a value on some other element.

Why does this matter?

Well, say you have some elements on a web page. You probably don't want them and their properties (font, margins, width, height etc.) to be the same size on a tiny mobile screen as on a giant 2560-by-1440 monitor.

Did you know? One CSS pixel does not equal one physical pixel of your screen. If this were the case, designs would be resolution dependent, i.e. things would appear much larger on lo-res screens than hi-res ones, where everything would appear too small. Browsers handle this with something called a reference pixel, which represents a physical pixel, and is calculated based on the device's pixel density and a typical user's distance from the display.

Of course you could use media queries to detect the screen size and adjust the styling for each element's properties accordingly, but this would be a lot of extra CSS, prone to inconsistencies, and hard to maintain as your site grows.

What if there was a better way to scale element properties, that didn't require you to specify exact values in so many places? That's where ems and rems come in.

Ems

For ems, this value is the font size of their (immediate) parent element. Take the following example markup:

<section>
<h3>I'm a heading</h3>
<p>I'm a paragraph sized with ems!</p>
</section>

And the accompanying CSS:

section {
font-size: 18px;
}

h3 {
font-size: 1em;
}

p {
font-size: 0.5em;
}

The paragraph's computed font size would be 9px, and the heading's would be 18px. If we wanted to increase this element's font sizes (but keep the ratio between the heading and paragraph size), we'd only need to update the font size of the section element. If we changed it to 20px, the heading would now be 20px, and the paragraph would be 10px. Definitely an improvement.

But there are problems with this approach. Because em sizing is computed based only on an element's direct parent's font size, this value changes in the case of elements nested more than one level deep. Let's extend our example:

<section>
<h3>I'm a heading</h3>
<p>I'm a paragraph sized with ems! <span>I'm a span inside the paragraph</span></p>
</section>
section {
font-size: 18px;
}

h3 {
font-size: 1em;
}

p {
font-size: 0.5em;
}

span {
font-size: 0.5em;
}

We've added a nested span element inside the paragraph, and set it to the same em value. However, its em value will be calculated based on the computed value of the paragraph (9px), which will produce a font size for the span of 4.5px! What we really meant was for the span to be the same size as the paragraph.

Rems to the rescue!

Rems (root ems) are similar to ems, except they compute their value based on the font size of the root element: html. With rems, we can nest as much as we like, and know that our sizing will always stay relative to the font size defined on html (set to a default of 16px in most browsers).

There are some cases where you might want more or less scaling than is achieved from a single root point. In these situations, if there are only a handful of cases, I normally find that making an exception for particular elements with media queries is fine. If there are more than that, you could try using ems inside encapsulated visual components, as Chris Coyier explores here.

Rems are now generally my measurement unit of choice, though there are a couple of things to bear in mind.

Browser support

If you need to support IE8, rems are not supported at all, though there is a polyfill. Also, IE9 & IE10 don't support rems when used in the font shorthand property (the entire declaration is ignored) or when used on pseudo elements.

Thinking in rems

Something I found annoying when starting to use rems was that it was hard to visualize even roughly what size something would turn out to be. You spend time trying to calculate the rem equivalent of a pixel value in your head. Plus, to achieve very specific sizing (maybe defined in px in a mockup by your designer), you can end up with ugly, difficult-to-remember decimal values in your CSS like 2.234215rem.

Luckily, there are ways we can just code pixel values, and then automatically convert those values to the equivalent rem value in our CSS output. This allows you to think in pixels, and means you'll never have to deal with 2.234215rem in your source code.

If you're using Sass, this function can help you achieve that:

$base: 16;

@function rem($pxval) {
@return ($pxval / $base) * 1rem;
}

It means you can just write:

font-size: rem(12); /* Outputs 'font-size: 0.75rem' based on a 16px root font size */

Or check out the postcss-pxtorem plugin for PostCSS.

Succeed in tech

Get actionable tips on coding, getting hired and working as a developer.

I won't spam you. Unsubscribe any time.