Skip to content

Instantly share code, notes, and snippets.

@JoeCianflone
Last active March 19, 2020 05:14
Show Gist options
  • Save JoeCianflone/ea4b3a1818f559f5c5798188fe4001a0 to your computer and use it in GitHub Desktop.
Save JoeCianflone/ea4b3a1818f559f5c5798188fe4001a0 to your computer and use it in GitHub Desktop.
Converting Pixels to Rem;s with a Simple Mixin

Did you ever notice that developers and designers have different languages? A designer, working in Photoshop or Sketch, will be talking about things in pixels. Designers make headers that are 48 pixels tall and have 60 pixel line-heights. Developers, like me, tend to think about things in percentages or EMs. We want font-sizes that are 4.8rem and line heights that are 1.6.

Today I want to resolve the pixel font-size issue with Sass.

Let's pretend you've got a new blog to code today. You crack open the design file and you see the following:

Main Header: 32px
Sub-Header: 28px
body copy: 18px

We can translate this to Sass like so:

.header--main {
   font-size: 32px;
}
.header--secondary {
  font-size: 28px;
}
article.copy {
  font-size: 18px;
}

Great so we're done right? Well, no. Pixel values mean you've cemented your font size and nothing is going to override them. If you have a user who likes to increase the size of their text by 200% your hard-coded pixel values won't change.

Most developers are going to opt to use EMs or REMs in this situation. So what does that look like? Well, we need to do a little math to get the right numbers here.

To calculate the EM/REM value we need to divide the font size by the base font size. As an example, browsers use a base font-size of 16px so if we wanted to convert 24px to rem we'd say:

24px / 16px = 1.5

Utilizing the formula our CSS now looks like this:

.header--main {
  font-size: 2rem;
}
.header--secondary {
 font-size: 1.75rem;
}
article.copy {
 font-size: 1.125rem;
}

Great. The only annoying thing here is that we need to run through this formula for every font size on our site. This could be simpler if we're using Sass because we could store the values in variables:

$font-size-large: 2rem;
$font-size-medium: 1.75rem;
$font-size-small: 1.125rem;

.header--main {
 font-size: $font-size-large;
}

.header--secondary {
  font-size: $font-size-medium;
}

article.copy {
  font-size: $font-size-small;
}

Better, but we still have to run this calculation every time we make a change. Also, what happens if we update our base font size? Since we're in Sass we're going to make this a function and make our lives easier.

What would make this easier is if we had a function that we can call and, on-demand, update our pixel values to rems. Something like the following:

.header--main {
   font-size: torem(32px);
}

.header--secondary {
   font-size: torem(28px);
}

article.copy {
   font-size: torem(18px);
}

This gives us the flexibility to deal with designers who will ask us things like, "can you bump that up 2 pixels?" and will also work in variables, so we could do something like this:

$font-size-large: torem(32px);
$font-size-medium: torem(28px);
$font-size-small: torem(18px);

Another nice side-effect of this is that it's way more understandable to everyone. Pixels make sense to most designers AND developers. I can think about pixels and get a general sense of how big something is going to be, but I can't do that with rem or em units. If a designer came to me and asked, "how big is that?" I can look at the code and say, "32px" and we both understand it.

Great, so you're sold, you want to start using this now right? Awesome. Let's see how it works under the hood:

$base: 100%;

@function val($n) {
    @return $n / ($n * 0 + 1);
}

@function torem($px) {
   $base-size: val($base / 100);
   $base-px-size: 16 * $base-size;

   @return (val($px) / $base-px-size) + rem;
}

If you want to see this in action check out the code on sassmeister

First thing we've got here is a variable that defines our base-font size. For all browsers the base font size is 100% and that works out to be 16px.

We're going to add that to our Sass like this:

html {
   font-size: $base;
}

Now if we swap out our base font-size we've got control of that number in a variable. We need this control because if our base size changes our rem calculation will be off.

Next comes the val() function. It's a neat little trick--we can use this to strip units off the end of something and turn it into a number. So, for example, 20px becomes 20. This is useful in our next function.

Our torem() function is the main event. We calculate the base as a number and convert it to a pixel value. Next we do the same calculation we did at the beginning of this article and boom, we've got the rem value!

The only other little trick here is we need to add the correct unit to the end of the number. We append things in Sass with the + sign, so wrap the whole value in parenthesis with a +rem and we're done.

I've used this function in countless projects since I've started writing Sass. I can't tell you how many times it has saved my bacon. This also helps to build a common language between developers and designers and that's crucial for project success.

Where you put this code depends on project structure, but I tend to keep it in a utility folder and keep the $base variable in my _variables file.

If you're using something similar or if this code helps let me know on Twitter. I'm @joecianflone there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment