Element 84 Logo

Responsive Typography: rem, em, and px

01.28.2019

Intro

Dealing with type on the web can be a challenge, especially when you have to account for the ever-changing range of screen sizes. Ultimately the font size(s) you use for headings, body copy, and whatever else directly effects the layout of you page, and when you’re dealing with dozens, or even hundreds of pages with differing content you need a flexible way to control type, while also keeping everything consistent. Fortunately we now have modular scales, such as rem and em to help with this.

I want to preface this by saying that there’s more than one way to tackle responsive typography, and I’m not going to go over all of them, but I’ll be showing my preferred method. Before we do that though let’s clear up any confusion there may be over rem vs. em vs. px and then discuss when it’s best to use each.

Pixels

I’m going to assume you already have a pretty strong grasp on pixels, they’re fixed in size, one pixel translates into a single dot on the screen. Our designs are created in pixels as well, so it’s natural to think that way when we go from design to code. The problem arises when we need to scale those designs across screen sizes.

What pixels (px) can be good for:

  • borders
  • base font-sizes
  • min-height (ie. hero images if vh isn’t viable or as fallback)

To be clear, it’s completely possible to create fully responsive websites using only px units by using a bunch of media queries to display specific font-sizes at each resolution. However, in doing so we quickly learn these pixel-specific sizes can become difficult to scale and a nightmare to maintain. This is where CSS3’s rem and em units of measurement come in handy—so let’s dive in.

Rem vs Em

I’ll start this off by saying I honestly wasn’t completely sure what the difference between rem and em was until recently, so if you aren’t either, don’t feel bad. Let’s clear this up once and for all…

Both rem and em are scalable units of size, but with em, the unit is relative to the font size of its parent element, while rem unit is only relative to root font size of the HTML document.

For me, realizing that the “R” in REM stands for “root” was what helped me to finally differentiate the two. Let’s check out a quick example to help clarify rem vs em.

Just some example CSS to show how rem will work, notice the root font-size is set using px via html tag

html, body { font-size: 16px; }
div { font-size: 18px; }
p { font-size: 1rem; }

And the corresponding HTML:


<xmp><div>
  <p>Lorem Ipsum</p>
</div></xmp>

Because the &lt;p&gt; tag is set to 1rem it ignores the parent div’s font-size of 18px. However, if we instead set the font-size to 1em, the paragraph would inherit the 18px font-size of its parent element. I know this example isn’t particularly useful, but hopefully it can help illustrate the difference between em and rem.

Best of both worlds

The best parts about the rem unit is that it allows you to quickly scale an entire project, across resolutions, just by setting the root font-size once per media query, and then scaling from there. You can do this a number of ways, but the simplest method is to set a base px font size, say 16px, and then use rem to inherit that base font size and scale it up or down for sizing of H1-H5, body copy, and even margins and padding. Let’s take a look:

This step is optional, but if you use Sass or Less it’s nice to set up reusable screen size breakpoints for your media queries.

$screen-sm: 768px;
$screen-md: 1024px;
$screen-lg: 1200px;
$screen-xl: 1600px;

Now we can use those screen size variables (or hard-coded values) to set staggered root font-sizes. Here we’re doing this mobile first, with a default font-size of 15px that applies to 768px and below screen sizes (most phones), up to 20px on extra large monitors or TVs.

body{
    font-family: 'Open Sans', sans-serif;
    font-size:15px;
    line-height:1.6;

    @media screen and (min-width:$screen-sm){
        font-size:16px;
    }

    @media screen and (min-width:$screen-lg){
        font-size:18px;
    }

    @media screen and (min-width:$screen-xl){
        font-size:20px;
    }
}

And now we can use the root font-size to scale our headings, and any other reusable or common elements.

h1 { font-size: 3rem;}
h2 { font-size: 2.5rem; }
h3 { font-size: 2rem; }
h4 { font-size: 1.5rem; }
h5 { font-size: 1rem; }

The downside, and the solution(s)

The above method makes it very easy to set up scalable type, but it unfortunately restricts our control of individual elements. For example, the above headings look great on larger screens, but once you drop down to mobile the headers are a bit too large.

There’s a few ways to solve this, including using rem for global elements and em for local, but the easiest would be to just add an additional media query, the resulting Sass would look like:


h1 { font-size: 2.4rem;}
h2 { font-size: 2rem; }
h3 { font-size: 1.6rem; }
h4 { font-size: 1.2rem; }
h5 { font-size: 1rem; }

@media screen and (min-width:$screen-sm){
  h1 { font-size: 3rem;}
  h2 { font-size: 2.5rem; }
  h3 { font-size: 2rem; }
  h4 { font-size: 1.5rem; }
  h5 { font-size: 1rem; }
}

Conclusion

There doesn’t seem to be an industry standard way of handling responsive typography yet, with some preferring to use em, some rem, and others a combination of the two. There’s even a growing group that say to never use px for font-sizes because it doesn’t allow the user to increase or decrease font-size in their browser settings. To be honest, there’s valid arguments from all sides, so it’s best to use the method that makes sense for the project you’re working on and the audience that it’s for.

One thing is for sure, setting a px root font-size, and then using rem to scale your type up or down from there—as I’ve done above— is super easy to grasp, scale, and maintain. Hopefully it will be of help to you too.