Pixels vs Rems

When to use a REM value and when to use a Pixel (PX) value in CSS.

What's the problem?

I remember a few years ago when people started learning about EMs and REMs - there was this whole bandwagon to make sure we always use them to ensure our sites are accessible. But I'm not sure that people truly understood what they were trying to achieve. Why were they better for accessibility than pixel values? Everyone I spoke to gave vague answers.

Some people assumed they were for when users were zooming in - yet in Chromium based browsers that actually bears little relevance for most things. So if it's not for zooming, then what's it for? Let's start by digging into what accessible features are available for sizing - don't worry, it's not a huge list.

Browser Zoom

As I've already mentioned it, I should probably start with browser zoom, most users will have seen this by pressing CTRL/CMD + +/-. In all Chromium based browsers, Firefox and Safari this causes the browser to zoom everything, effectively increasing the size of images, text, padding and margins accordingly.

It's designed so that applications that don't use relative units, or at least don't use them properly will still give the user the best possible experience.

The most important thing to know about this is that it makes no difference to our relative units whatsoever.

Chrome appearance settings with font-size set to Medium

Browser Text Resizing

Most browsers have the ability to resize the base font-size now, but what do we mean by the base font-size?

If you were to put a <p> tag in a HTML document with some dummy text in and inspect, there's a good chance that your browser would render that at 16px, that's because the base font-size is set to 16px at the root level.

Relative units then use this 16px base font-size to compute their values, we'll talk more about this later, but when you change your base font-size is Chrome, you get a choice of 5 values, each will change what that 16px really is:

  • Very Small 9px

  • Small 12px

  • Medium 16px

  • Large 20px

  • Very Large 24px

Custom Stylesheets

Whilst it's impossible to actually say what's in a custom stylesheet, these are usually set by the more technically adept users, allowing them to change values to what suits them best.

The most common change here is to find the body tag and change the font size to a pixel value that suits the user.


What are Relative Units good for?

So I'm making the assumption that we all know what a pixel is, but now we've got these relative units such as rem and em each with it's own unique purpose.

A rem unit or a root em computes it's value as a multiple of the base font-size. Meaning that a default 16px base font-size computes as such:

  • 0.5rem = 8px

  • 1rem = 16px

  • 1.5rem = 24px

  • 2rem = 32px

Whereas our em units compute their size relatively based on the current font size. This makes them much harder to calculate.

html
<h1 style="font-size: 24px">
    Hello
    <small style="font-size: 0.5em">
        World
    </small>
</h1>

In the example above, we can see that our h1 tag is set to 24px and the small tag is set to 0.5em which will compute as 0.5 * 24 so 12px.

For CSS properties such as line-height, most browsers will consider a unitless value as being an em, so line-height: 1.5 is usually the same as line-height: 1.5em which is 1.5 * the font size.

When I'm building out my typography scales it's not uncommon to find something akin to this in my apps:

css
.text {
    font-family: Arial;
    font-size: 1rem;
    line-height: 1.3em;
}

.text--xl {
    font-size: 2rem;
}

.text--lg {
    font-size: 1.5rem;
}

.text--sm {
    font-size: 0.75rem;
}

.text--xs {
    font-size: 0.5rem;
}

Because the .text class has an em value set for line height, assuming that I want to keep a 1:1.3 ratio (which I usually do) then that will compute against the updated font-size values in the modifier classes.

Using this example we can now see that .text--lg, when users change their font size in chrome will compute it's sizes as such:

  • Very Small 13.5px

  • Small 18px

  • Medium 24px

  • Large 30px

  • Very Large 36px


What are Relative Units not good for?

So we can see where relative unit's are great for fonts, line-heights, spacing between lines... those tricky things where partially sighted users often struggle, but that doesn't make them automatically the best unit for everything.

Consider a border radius:

css
.border-radius--px {
    border-radius: 8px;
}

.border-radius--rem {
    border-radius: 0.5rem;
}

This is a problem I see a lot, whilst not the biggest problem in the world, it illustrates the issue - usually a border radius is set because it looks good for the brand, in Apple's case they even own the legal rights to the curvature for their product's casing.

By using a fixed px value, regardless of what the user's font-size is set to, they will always see that fixed pixel value, however, when you use a relative unit such as a rem you run into the problem of that font-size actually changing the value.

I've mocked up these simple images which show what happens when the border-radius changes from 8px to 16px to 32px to highlight the problem. For most applications, this is probably not a desired experience.

200px by 200px grey square with a 8px border radius200px by 200px grey square with a 16px border radius200px by 200px grey square with a 32px border radius

Now let's discuss margins, paddings and gaps.

These are our spacing units which we use to separate our content into easier to digest chunks, and the knee-jerk reaction now could be to pick either rems or px values for these, and the answer... well there really isn't one but I follow a simple rule:

For spacing between text content: use relative units - as text could become unreadable with a fixed value.

For paddings and margins between blocks such as cards: use fixed values - as text becomes bigger it doesn't make sense to reduce the space available.


What about Media Queries?

Now the only thing left really to discuss are our media queries. As most developers tend to think about these in terms of pixels - and that's ok! But what if we can go a little further?

If we consider that our smaller screen experiences are better for users with a smaller font-size to screen real estate ratio, then surely it follows that as users increase the size of their font that we should offer up these experiences.

We can do that by simply converting our px values into em values - simply divide by them 16.

With fixed pixel values
css
@media (min-width: 768px) {
    ...
}

@media (min-width: 1024px) {
    ...
}

@media (min-width: 1200px) {
    ...
}
With relative units
css
@media (min-width: 48em) {
    ...
}

@media (min-width: 64em) {
    ...
}

@media (min-width: 75em) {
    ...
}

By swapping your pixels to rems here you're ensuring that as the font size increases / decreases, so does the threshold at which your media queries activate, thusly (ooh I love that I got to use that word in an article) ensuring that your user is more likely to see an experience tailored for their screen size and their level of browser zoom.

In Summary

It's simple, there's no one-size-fits-all here, but by putting some forethought into which unit you're using to do what, you can make a massive impact to your customer's experience - after all, that's what were all here for.