Magic Patterns Logo
CSS is Hard: Understanding Pixels vs Ems vs Rems5 minutesTeddy Ni


CSS is hard. Really hard sometimes.


Font size is something that seems simple on the outside, but I see products mess it up all the time.


You might wonder, who cares? It's just a font size, right?


Font size is a critical aspect of web accessibility. If you're not careful, you could find yourself getting sued.


TL;DR:

  • Use pixels for precise or static measurements
  • Use ems if you need to support old browsers (IE8 or earlier)
  • Use rems for font sizes and spacing

To get a better understanding of the tradeoffs and when to use which, continue reading!

Pixels

I've found that newer developers tend to default to pixels. Understandably so — pixels are the most straightforward way to match a design and are easy to understand.


FUN FACT

By the CSS Standard, 1 pixel is 1/96 of an inch.


However, using pixels as your unit for font sizes comes with a couple of downsides:


  • It's not naturally responsive. 1/96 inch will always be 1/96 inch, regardless of screen size
  • Not meeting web accessibility standards. Users with vision impairments may have browser settings that increase the default size of the text. Pixels, being fixed, do not respond to these settings.

Wall

Ems

In CSS, the em unit is used to define the size of an element relative to its parent container or the font size of the element itself.


FUN FACT

Em stands for "em-height", which traditionally refers to the height of the capital letter "M" in a given font. However, this definition has evolved to simply refer to the current point size.


For example, consider this example snippet of code:

<html style={{ fontSize: '16px' }}>
  <body style={{ fontSize: '1.5em' }}>
    <div style={{ fontSize: '1em' }}> Hello World </div>
  </body>
</html>

❓ What size font in pixels do you think the Hello World gets rendered at? If you guessed 24px, you would be correct!


Let's break it down — take a deep breath, as it's a lot of math 😅


“Hello World”s font size is defined as 1em, meaning it will simply be equal to whatever font size it inherits. In this case, its parent <body> has a font size of 1.5em. We now need to go one more layer higher, to the <html> tag to see that the <body> tag will have a font size of 1.5 * 16px = 24px. And because the “Hello World” has the same font size as the <body>, our “Hello World” will also be rendered at 24px.


Whew, that was a lot of math for a simple example!


Naturally, one of em's disadvantages is that it is harder to calculate. Its value is dependent on a variety of factors such as its inherited font size and its own font size.


In addition to this, it's hard to be precise since it's not a hard fixed value. If you need to specify a precise size of an element, such as a button or graphic, em units may not be the best choice.


The advantage of em comes in when there are any changes to the default document font size. Because these units are relative to the parent, any changes to the default document font size for accessibility reasons also scales any text using em.


In the above example, if 16px is changed to 32px, “Hello World” will automatically change to 48px even though the font size only changed in one spot.

Vault

Rems

Welcome rem, where em and pixels meet in the middle. Rem stands for “root em”, referring to the fact that Rem is relative to the font size of the root element (usually the <html> tag). For example, let's consider the above snippet, but replace em with rem.

<html style={{ fontSize: '16px'}}>
   <body style={{ fontSize: '1.5rem' }}>
      <div style={{ fontSize: '1rem' }}> Hello World </div>
   </body>
</html>

❓ What size font in pixels do you think the Hello World gets rendered at?


Our calculation becomes much simpler compared to em. We know that the root element, aka the <html> tag, has a font size of 16px. And because our “Hello World” is being rendered at 1rem, it will simply be 1 * 16px = 16px. Much easier than needing to traverse up the tree to figure out what 1em is!


Similar to em, rem is not great for precise measurements or things that should be statically defined. Rem is also relatively new — if you need to support IE 8 or earlier, you would be best sticking to em.


TRY YOURSELF

This page uses rem. Try changing your browser's default font size and see how the text changes!


If you are using Chrome, you can change the default font size in Settings > Appearance > Font Size

In Conclusion

We understand that the tradeoff of speed (using pixels) and accessibility is a tough decision to make. Sadly, most developers teams end up picking speed over accessibility.


  • Use Pixels for precise or static measurements or to sprint something out
  • Use Ems if you need to support old browsers (IE8 or earlier)
  • Use Rems for font sizes and spacing

This is a general rule of thumb, but hopefully this paints a deeper understanding of how these units work so you can make the correct tradeoff evaluations yourself!

The Future

At Magic Patterns, we want to make this tradeoff irrelevant. We believe that with the power of AI, development velocity should as easy as typing in what you want. And it should be accessible by default.


If you're interested learning how to use your custom design system with Magic Patterns, schedule a demo to speed up your development process.

Community