Ems, rems or pixels?

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 no longer enough to just define sizes for everything in pixels.

Why not?

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.*

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. 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.

Relative units

em and rem units are relative, meaning they have no fixed size, but instead are sized relative to a value on some other element.

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>
</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 visualise 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 Photoshop by your designer), you can end up with ugly, difficult-to-remember decimal values in your CSS like 2.234215rem.

Then I discovered Bourbon has a Pixels to Rems function, which solved this problem. It takes a pixel value and converts it to rems, allowing you to think in pixels, and meaning you never have to deal with 2.234215rem values. If you're using Sass, this means you can just write:

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

Bourbon is awesome and useful for lots of other things, but this function is also small enough that you could adapt it and include it in your project on its own too:

$base: 16;

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

* To clear up confusion, 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. How browsers handle this is 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.