A SASS Mixin to accommodate @font-face fallbacks

I’m a fan of webfonts, like just about every designer and developer out there. I actually am more of a fan, though—I consider them essential on mobile experiences as well. Figure out a way to reduce your bandwidth and include a custom font. Makes all the difference. Assuming you can use it well.

In the past, I’ve self-hosted all fonts for web projects. Currently, I’m dipping my toes into fonts hosted by TypeKit.

Well, having the fonts hosted on a different server seems to add to the lag time significantly, and I’m noticing the FOUT, or Flash Of Unstyled Text. I think, in the end, I’m going back to self-hosted fonts for this project, too. But for now, let’s assume you have a project, and you need third-party hosted fonts.

And you’re using SASS.

Well, if your chosen font is smaller or larger than any fallback font you can use, then that FOUT is going to be more noticeable.

You may want to adjust your font-size and your line-height to accommodate. If we are using TypeKit, the HTML tag has a class immediately applied via JavaScript called .wf-loading. (More info here) When the fonts are loaded (or not) after 3 seconds (you can change that value), then that class is changed to either .wf-active or .wf-inactive.

My first thought? Just apply this to the body and we’re done, e.g.:

body {
  font-size: 1em;
}

.wf-active body {
  font-size: 1.25em; /* increase to compensate for smaller x-height */
}

The problem is this does not account for line-height. So how about…

body {
  font-size: 1em;
  line-height: 1.5;
}
.wf-active body {
  font-size: 1.25em; /* increase to compensate for smaller x-height */
  line-height: 1.2; /* = 80% of line-height, compensating for larger font size */
}

Okay, that works, but then, since I like working in EMs for layout, I realize that everything will resize. Kind of defeats the whole purpose.

So, I think it falls to us to do this for all text elements, and no layout elements. That’s a bit cumbersome, but it’s definitely time to use SASS to make this easier.

For starters, let’s add a ratio which we can tune:

$font_size_adjust: 1.25

Now, we can create a mixin that we can use in multiple places.

@mixin font_size_lh( $fontSize, $lineHeight ) {
  .wf-active & {
    font-size: $fontSize * $font_face_adjust;
    line-height: ($font_lh_body/$font_face_adjust);
  }
}

(Note: You have to enclose division in parentheses, because the slash is allowed in CSS, and SASS knows this, and so, well, just do it.)

SASS usage is as follows:

p {
  font-size: 1em;
  line-height: 1.5;
  @include font_size_lh( 1em, 1.5 );
}

And your CSS output is:

p {
  font-size: 1em;
  line-height: 1.5;
}

.wf-active p {
  font-size: 1.25em;
  line-height: 1.2;
}

Nice, but we could simplify that—why call the font-size and line-height twice? And I also wanted to base everything in my design on the desired font, not the fallback.

This led me to the following. Note the math is switched around:

@mixin font_size_lh( $fontSize, $lineHeight ) {
  font-size: $fontSize;
  line-height: $lineHeight;

  .wf-loading & {
    font-size: ($fontSize/$font_face_adjust);
    line-height: $font_lh_body * $font_face_adjust;
  }
}

SASS usage, followed by CSS output:

/* SASS */
p {
  @include font_size_lh(1em, 1.5);
}

/* CSS OUTPUT */
p {
  font-size: 1em;
  line-height: 1.5;
}

.wf-loading p {
  font-size: 0.8em;
  line-height: 1.875;
}

Now, that’s a format I don’t mind typing several times, and I can probably live with.

But, you know what’s simpler?

Self-hosting the fonts.

So whatcha think?

I’d love to hear from you.

Leave a Reply