We've been styling fonts for years using ems with this technique: http://www.alistapart.com/articles/howtosizetextincss

But I think its time to change to this method: http://snook.ca/archives/html_and_css/font-size-with-rem

That method uses rems with a px fallback. The browser support is ok; see http://caniuse.com/#search=rem

Sizing with em is hard, especially when you want to change font sizes. Since the font size cascades and all font sizes are relative to the parent, you end up having to recalculate a lot of em values. :-p And there's no easy way to automate that math with Sass since Sass doesn't automatically know what the parent elements font size is.

But with a px fallback, we can easily create a Sass mixin to write px fallback and then rem.

Comments

Status:Active» Needs work

Rough draft of a sass mixin

// All browsers use a 16px default font size, but let it be overridden.
$rem-base-font: 16px !default;
// Add font-size and line-height with rem units, using px as a fallback value.
@mixin font-rem($font-size, $line-height: 0) {
  font-size: $font-size;
  font-size: ($font-size / $rem-base-font) * 1rem;
  @if ($line-height > 0) {
    line-height: $line-height;
    line-height: ($line-height / $rem-base-font) * 1rem;
  }
}

Status:Needs work» Postponed

Status:Postponed» Active

Here's a more recent draft:

$base-font-size: 16px !default;
$base-line-height: 24px !default;
// For the given property, use rem units with px as a fallback value.
@mixin rem(
  $property,
  $size,
  $root-font-size: $base-font-size
) {
  #{$property}: $size;
  #{$property}: ($size / $root-font-size) * 1rem;
}
// Add font-size and line-height with rem units, using px as a fallback value.
@mixin rem-font-size(
  $font-size,
  $line-height: false,
  $root-font-size: $base-font-size
) {
  @include rem(font-size, $font-size, $root-font-size);
  @if ($line-height != false) {
    @include rem(line-height, $line-height, $root-font-size);
  }
}
@function rem(
  $size,
  $root-font-size: $base-font-size
) {
  @return ($size / $root-font-size) * 1rem;
}

In addition, I'm going to see what might be useful in this Compass plugin https://github.com/JohnAlbin/rem and see about adding proper rem support to Compass' vertical rhythm mixins.

Priority:Normal» Major
Issue tags:+7.x-5.0 blocker

One complication is Compass' vertical rhythm mixins don't provide px backups when using rem. We may have to fork some of those mixins and put them in a custom partial.

I'm working on some stuff with another Compass developer over here: https://github.com/JohnAlbin/rem

This is a release blocker.

Issue tags:-7.x-5.0 blocker

BAh. I realized I'd have to fork Compass' vertical rhythm mixin to get this into 7.x-5.0 at this point, because it lacks the "px as fallback" support that any good rem solution would need.

I'll keep working on this, because it's awesome!

Wow not heard of rem's until now, this would be a fantastic addition.
However as we are currently using em's throughout wouldn't it be better to fallback to them instead of px's?

FYI... I think this has been committed to compass and should be in the next release, see https://github.com/chriseppstein/compass/pull/896.

Version:7.x-5.x-dev» 7.x-6.x-dev

Not sure when this new version of Compass will land. But I'm moving this to 7.x-6.x in the meantime.

rem support is currently in 0.13.alpha.4, the following vars just need to be set, and all vertical rhythm mixins will automatically output rem with pixel fallbacks.

$rhythm-unit                : rem;
$rem-with-px-fallback : true;

The following rem mixin from https://github.com/nex3/sass/issues/472 works quite well. With Sass changes in future releases, it'll slim up a bit. I don't think there is a current rem mixin like this in the next release of Compass though, so we'll definitely need some sort of iteration on it. (which i see John is already on)

// REM
// Output a given style rule containing rem values along with an (optional)
// fallback rule for older browsers (with rem values converted to px).
//
// Params:
//   $property        - The css property name.
//   $px-values       - The value (or space-separated list of values) for the property.
//   $use-px-fallback - [ true | false ]
//
@mixin rem($property, $values, $use-px-fallback: $rem-with-px-fallback) {
  // Create a couple of empty lists as output buffers.
  $px-values: ();
  $rem-values: ();
  // Loop through the $values list
  @each $value in $values {
    // For each property value, if it's in rem or px, derive both rem and
    // px values for it and add those to the end of the appropriate buffer.
    // Ensure all pixel values are rounded to the nearest pixel.
    @if type-of($value) == number and not unitless($value) and (unit($value) == px or unit($value) == rem) {
      @if unit($value) == px {
        $px-values: join($px-values, round($value));
        $rem-values: join($rem-values, convert-length($value, rem));
      }
      @else {
        $px-values: join($px-values, round(convert-length($value, px)));
        $rem-values: join($rem-values, $value);
      }
    }
    @else {
      $px-values: join($px-values, $value);
      $rem-values: join($rem-values, $value);
    }
  }
  // Use pixel fallback for browsers that don't understand rem units.
  @if $use-px-fallback {
    #{$property}: $px-values;
  }
  // Use rem values for everyone else (overrides pixel values).
  #{$property}: $rem-values;
}