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);
}
Would it not be a ton easier with setting a base font size of 10px on the or some root element and the 1em will always be 10px? And you would only work with em. So it would be very easy to calc px. (32px = 3.2em).
It is not clearly mentioned here but em is looking up the dom tree for thE first font-size.
Why would you base your entire font structure on a font size that small though? 10px would require you to change your font size on nearly element on the page just so that you could save yourself a little math?
What do you mean by changing the font size on each element?
If you want “elastic” or responsive font size you need to declare that anyway for each component, just like this article shows.
Just take 5 minutes and compare the 2 approaches. It’s not about avoiding math, it’s about making development easier for your team.
sass is rock !!
specially when you know some of programming concepts like functions , variables , if condition .. etc
i didn’t engage with it a lot but seems like a life saver
re: Jesse’s comment
Jesse is correct in that setting a base font of 10 would involve adjusting the font size on many more elements than would be necessary if your natural font size is > 10. It is incorrect to state that you would need to set font-size on every element for a responsive site.
Consider the following snippet:
… Now set font size to 13px (or whatever your base size is):
If you set the base font to 10 (which is quite small!), you would end up with specifying font-size on classes red and blue if you want them to be the equivalent of a base size other than 10 for normal text. This is too much work compared to using a function to adjust the font-size.
Hi Chris,
I love this mixin but I’m wondering how to make it accept shorthand.
I would like to be able to use this for any property measurement – i.e. padding: em(10 20 15 0);
I believe bourbon and compass have this built in but I prefer not use them if possible.
I’m also wondering if there’s any value to converting to REM rather than EM.
Thanks for all you do!
Hi Travis,
I wrote the article for Chris. Sorry I’m only just seeing this as I was reading the comments. These are sass functions which are a little less flexible than mixins.
You could use this for short hand currently like so:
padding: em(10) em(20);
which isn’t quite what you are asking but the only way to do it with the functions listed above. I’ll see if I can work out a mixin using these functions and get back to you here.Thanks!
And I missed answering one of your questions.
For a great REM mixin, check out this awesome article by Hugo Giraudel:
Thanks for this helps a lot with the process, instead of having to use calculator back and forth!
Hey Sean/Chris
Really like the solutions using Sass’s unitless function, but found that if the context is an em value then it still returns an px value, instead of an em value
I fixed that for me by checking for the em unit for context first, then stripping the units before doing the calculations then converting the final result to em.
Here is an pen to illustrate the difference:
Hey Jero, I read your comment and wanted to make sure I would avoid the issue you’re describing but wasn’t sure how to recreate it.
Tried following your example but was still confused.
Can you help me understand why px were being returned in some cases?
When attempting to implement this into a bootstrap template, I ran into this issue: Error: Undefined operation: “1rem times 1.25”.
Here’s the code that triggered the issue:
$font-size-context: 15;
$font-size-base: rem($font-size-context);
As a solution, I found this revised version of the function fixes it:
@function rem( $pixels, $context: $font-size-context ) {
@return ($pixels/$context)*1rem;
}
Just a heads up to anyone else who may have this issue, since I hit my head for awhile trying to figure out what was going on. Thanks for the em() idea!
Here is the function for rem
Hi! I have a big doubt:
does it work when scaling fonts in different viewport sizes???
since we set the default to be always 16px
thanks :)
I just configure :root and sets the size props there
Hi, is there any way to multiply em() value?
Example:
$padding: em(10);
if I need em(20) so I want to multiply that var.
$padding*2 but not working
Maybe i’m misunderstanding something, but doesn’t this defeat the purpose of using em units?
If we’re setting a static $context value, then our target isn’t inheriting the font size from its ancestor like ’em’ units should.
Same here.
I guess we’re talking about
rem
here, notem
?