Code    5 min read

Convert pixels to rems automatically

Convert pixels to rems automatically

Using rems in your CSS is a great way to deal with the many hurdles you’ll face building out a design across various screen resolutions.

Before we get ahead of ourselves assuming everyone knows what we’re talking about, here’s a quick primer on rems if you’re uninitiated. Feel free to skip this part if you’re already in the know.

A rem stands for “root em” and our buddy Jonathan Snook tells us that “the rem unit is relative to the root-or the html-element. That means that we can define a single font size on the html element and define all rem units to be a percentage of that.”.

In most modern browsers, 1 rem is equal to 16 pixels. So with a base size of 1rem (a.k.a. 16px) set, we can now use simple division to figure out proper sizing of elements. A headline that is 24px in Sketch is coded as 1.5rem because you take 24px and divide it by the base font size of 16px. This relative unit conversion makes scaling fonts and layouts with media queries a breeze.

But this leads us to one of the biggest criticisms of using rem units in CSS: the insane amount of calculating it takes to get a design comp from pixels to rems.

We know that using relative units of measurement are a great way to handle responsive web design. But using a rem to pixel conversion tool over, and over, and over again gets a tad bit monotonous. There has to be a better way, right? Lucky for us, there is.

A quick word about workflow

Before we get started though, it’s important to note that this method only works if you have a pre-processor in place. We use SCSS and Codekit to handle our dirty work. If you need help setting these up, Codekit’s documentation is a great place to start. Now, onward!

Finding a way to convert pixels to rems automatically

In our search for efficiently managing rems, we inspected our own process. One things we did know: we wanted to have a 1:1 hand off from designers to developers. But what does that mean?

That means if a designer makes a headline 24px with bottom margin of 36px, we wanted that reflected in the code and easily identifiable.

We also knew that we didn’t want to waste the developer’s time dividing a ton of numbers by 16px to get a rem percentage for our responsive layout. That’s no fun.

So after turning over a lot of stones, we settled on a combination of ideas from Foundation and a mixin article from CSS Tricks. The end result is a function that will convert pixels to rems on the fly. Here’s the code, we’ll break down how it works in a minute:

$global-font-size: 100% !default;

/* 
Removes the unit (e.g. px, em, rem) from a value, returning the number only.
@param {Number} $num - Number to strip unit from.
@returns {Number} The same number, sans unit.
*/

@function strip-unit($num) {
  @return $num / ($num * 0 + 1);
}

/* 
Converts one or more pixel values into matching rem values.
@param {Number|List} $values - One or more values to convert. Be sure to separate them with spaces and not commas. If you need to convert a comma-separated list, wrap the list in parentheses.
   
@param {Number} $base [null] - The base value to use when calculating the `rem`. If you're using Foundation out of the box, this is 16px. If this parameter is `null`, the function will reference the `$base-font-size` variable as the base.
   
@returns {List} A list of converted values.
*/

@function rem-calc($values, $base: null) {
  $rem-values: ();
  $count: length($values);

  /* If no base is defined, defer to the global font size */
  @if $base == null {
    $base: $global-font-size;
  }

  /* If the base font size is a %, then multiply it by 16px 
     This is because 100% font size = 16px in most all browsers
  */
  @if unit($base) == '%' {
    $base: ($base / 100%) * 16px;
  }

  /* Using rem as base allows correct scaling */
  @if unit($base) == 'rem' {
    $base: strip-unit($base) * 16px;
  }

  @if $count == 1 {
    @return -to-rem($values, $base);
  }

  @for $i from 1 through $count {
    $rem-values: append($rem-values, -to-rem(nth($values, $i), $base));
  }

  @return $rem-values;
}

/* 
Converts a pixel value to matching rem value. *Any* value passed, regardless of unit, is assumed to be a pixel value. By default, the base pixel value used to calculate the rem value is taken from the `$global-font-size` variable.

@access private
@param {Number} $value - Pixel value to convert.
@param {Number} $base [null] - Base for pixel conversion.

@returns {Number} A number in rems, calculated based on the given value and the base pixel value. rem values are passed through as is.
*/
@function -to-rem($value, $base: null) {
  /* Check if the value is a number */
  @if type-of($value) != 'number' {
    @warn inspect($value) + ' was passed to rem-calc(), which is not a number.';
    @return $value;
  }

  /* Transform em into rem if someone hands over 'em's */
  @if unit($value) == 'em' {
    $value: strip-unit($value) * 1rem;
  }

  /* Calculate rem if units for $value is not rem or em */
  @if unit($value) != 'rem' {
    $value: strip-unit($value) / strip-unit($base) * 1rem;
  }

  /* Turn 0rem into 0 */
  @if $value == 0rem {
    $value: 0;
  }

  @return $value;
}

Taking a look at the conversion process

Let’s say you have a file called styles.scss. To implement, you place this function at the top of the file so you can call on it throughout the cascade. Once you have your file in order, you simply pass the function rem-calc() where you want to output pixel-to-rem values. The arguments can either be a single number or multiple numbers, separated by a space (see examples below).

Let’s take a simple example of adding bottom margin to a container div with a class of .container.

<div class="container">
  <p>Content here</p>
</div>

To add 10px of bottom margin, you would add your CSS like this using the function value from above:

div.container {
  margin-bottom: rem-calc(10); /* 10 is the amount of margin you want in pixels */
}

Once run through the processor, you’ll see the output as:

div.container {
 margin-bottom: 0.625rem; /* 10 divided by 16 */
}

To use this function with multiple parameters, setting up multiple margins in your CSS would look like this:

div.container {
  margin: rem-calc(11 16 12 8); /* Numbers are the amount of margin you want in pixels */
}

With the output after processing being:

div.container {
  margin: 0.6875rem 1rem 0.75rem 0.5rem; /* All margins divided by 16 */
}

A practical way to make your site more flexible

Most design tools output their values (distances, font sizes, dimensions, border widths, etc.) in pixels. With this function, you won’t have to worry about making those pesky conversions anymore.

Designers are happy because their designs stay true to scale. Developers are happy because they don’t have to whip out their calculators every 5 minutes.

The end result are more flexible web sites and applications and a delighted team. It doesn’t get much better than that!

Written by @mattdowney

Did you like that article? Sign up for our weekly newsletter and we'll send you more like that every Friday. 🙌

When you subscribe to our newsletter, you'll get the inside scoop on all the latest happenings around the 45royale camp. More importantly, we'll send you resources to help you refine your own design and development process, harness agility in your creativity, and stay inspired to meet your work with fresh eyes. Sound good? Giddyup!

Loading

Spam is an enemy we all share. Sort of like the White Walkers. As such, we’ll never share your email address with anyone. Oh, and if you're still not convinced our newsletter rules (it does, trust us) check out previous issues, homie.

Leave your comment below