Since a while now word has spread to use the CSS unit rem
for font-sizes and values in CSS. Here I want to explain how you can use a fallback in Sass or LESS to get rem
working in all browsers.
Why rem?
Let’s look into what rem
means. We know of the em
unit which is relative to the font-size of the parent element it is defined on. This means if one of the parents in the DOM-tree changes its font-size, the font-size of the child element changes too. In contrast the rem
unit is relative to the root element of the page (this means the html
element). Thus it is possible to define a font-size once on the root and make all other sizes depending on this size. Please switch over to Snook’s blogpost explaining what rem
is to get more information about it.
If you ask yourself why you should use em
instead of px
, Chris Coyier wrote an article on why he switched to em
instead of pixels a while ago for nearly all properties using units in CSS. Read this to understand why em
and thus rem
is so important.
I would encourage you to use rem
(or at least em
) for properties like padding
, margin
and sometimes even width
instead of pixels. It makes your design even more responsive.
The drawback of rem
is that it is not supported in all browsers that are used, even though the support looks pretty good: Internet Explorer is capable of dealing with rem
since version 9. The versions before need a fallback. It is supported on the major mobile browsers except Opera Mini. Let us have a look on how we can define such a fallback using Sass or LESS.
A Sass Mixin
In order to get the pixel-based auto-calculation working as a fallback we need to define the font-size as a variable in Sass or LESS.
The following examples are in Sass with the SCSS-syntax.
$main-font-size: 16px;
We can now use this default font size on the root element:
html { font-size: $main-font-size;
Now we define a mixin that provides a fallback pixel-based size of the property based on the variable we defined before and in rem
for capable browsers.
@mixin x-rem ($property, $value) { #{$property}: $value * $main-font-size; #{$property}: #{$value}rem; }
What the mixin does is, that it takes the $property
and calculates the value in pixels. This simple mathematic function is part of Sass. The $value
argument is a decimal digit.
I like to prefix my own mixins with x-
to easily distinguish them from other mixins. This is a part of the Idiomatic CSS principles by Nicolas too. I think previously I prefixed them with a namespace (mostly it was the-
as a prefix, so you get the-transition
) – but since there is a better convention with Idiomatic CSS I switched to it.
This mixin can be called like in the following examples:
@include x-rem(font-size, 1.4); @include x-rem(padding-left, 2);
The output that is being produced looks like this for the first example:
font-size: 22.4px; font-size: 1.4rem;
You can use Sass’ round()
function to get an integer output for the px-based output. But every browser is capable to round 22.4px
by itself to 22px
since it is not possible to display 0.4px after all. (LESS has the same function.)
A Few Words On The LESS Mixin
In LESS interpolation for properties is current not possible with version 1.3.x. The maintainers aim to include it in version 1.4. For the time being we need to define a workaround for properties which is basically a JavaScript function which returns a sting that consists of two properties instead of one, while the first one is -
which is basically no property an thus disregarded by the browser. The second is the property that we want to use.
Here is the first line of the mixin:
-: ~`(function () { return ';@{property}: @{px-fallback}'; }())`;
This only works if the LESS compiler uses the actual JS library. It does not work with lessphp or other compilers that are not JavaScript based.
Final Words
And that is it. The mixin provides a decent fallback for rem
-based sizes of all kind. Since CSS runs stable with this version of a fallback and overwrites the pixel-based value because of CSS’ cascade we can use it without any problems. It works in old Internet Explorers.
Life is easy with rem
. So look at the Gist and use the rem-fallback-mixins.
Credit
I want to mention that I first saw this technique used by Divya Manian a year ago (beginning of 2012) when working on the HTML5 Please API project. I am not sure who developed this technique or where it comes from. Please let me know if you have a link.
Addition: The Susy framework has a Sass mixin which lets you easily convert units including the rem unit and a fallback as described here. (Head-tip Fabian Beiner.)
Addition 2: Steffen wrote a Sass mixin which lets you use the short notation of properties like margin
or padding
. Even mixing values as px and rem is working. Cheers!