Ems, rems or pixels?15 Aug 2015
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.
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.
rem units are relative, meaning they have no fixed size, but instead are sized relative to a value on some other element.
For ems, this value is the font size of their (immediate) parent element. Take the following example markup:
And the accompanying CSS:
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:
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
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.
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
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:
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:
* 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.