Px to Em Functions

Avatar of Chris Coyier
Chris Coyier on

We’ve talked about “Why Ems?” here before.

For those new to em values, The Mozilla Developer Network does an excellent job of explaining ems:

…an em is equal to the size of the font that applies to the parent of the element in question. If you haven’t set the font size anywhere on the page, then it is the browser default, which is probably 16px. So, by default 1em = 16px, and 2em = 32px.

If you still prefer to think in px, but like the benefits of em, no need have your calculator handy, you can let Sass do the work for you. There are a variety of ways to calculate ems with Sass.

Inline math:

h1 {
  font-size: (32 / 16) * 1em;
}

p {
  font-size: (14 / 16) + 0em;
}

Note: We need the “* 1em” there for Sass to correctly append the unit value. You can also use “+ 0em” for the same purpose.

Result:

h1 {
  font-size: 2em;
}

p {
  font-size: 0.875em;
}

This works, but we can make it easier.

The em() Sass function

There are quite a few different ways to write this function, this one from a Web Design Weekly article:

$browser-context: 16; // Default

@function em($pixels, $context: $browser-context) {
  @return #{$pixels/$context}em;
}

Super clever! This function uses Sass’ string interpolation to append em to the value. Note that the $context parameter has a default value of $browser-context (so, whatever you set this variable to). This means that when calling the function in your Sass, you only need to define the $pixels value and the math will be calculated relative to $browser-context – in this case – 16px.

Example Usage:

h1 {
  font-size: em(32);
}

p {
  font-size: em(14);
}

Result:

h1 {
  font-size: 2em;
}

p {
  font-size: 0.875em;
}

A similar function using math instead of string interpolation from The Sass Way can easily be modified to accept variables like our string interpolation function:

//un-modified

@function calc-em($target-px, $context) {
  @return ($target-px / $context) * 1em;
}

// and modified to accept a base context variable

$browser-context: 16;

@function em($pixels, $context: $browser-context) {
  @return ($pixels / $context) * 1em;
}

Another using Sass’ unitless() method:

$browser-context: 16;

@function em($pixels, $context: $browser-context) {
  @if (unitless($pixels)) {
    $pixels: $pixels * 1px;
  }

  @if (unitless($context)) {
    $context: $context * 1px;
  }

  @return $pixels / $context * 1em;
}

This allows us to either include the px unit or not in the function call.

h1 {
  font-size: em(32);
}

// is the same as:

h1 {
  font-size: em(32px);
}