Last Updated: May 30, 2016
·
2.447K
· artinruins

A Mixin for Font-Size-Adjust

Anyone who has worked with custom webfonts has probably run into an issue where they needed the font-size-adjust</code> property. Unfortunately, Firefox is the only major browser that supports it so far (late 2012).

The Problem

In a nutshell: You have a custom webfont in your design. If the webfont is not loaded or supported, the backup default font (usually Arial) has a very different x-height, and all your headlines and places where you use the webfont now look like they are screaming. In short, there is a glaring difference between the way the webfont looks and the way the fallback fonts look.

The way font-size-adjust is meant to solve it

<a href="//webdesignernotebook.com/css/the-little-known-font-size-adjust-css3-property/">Others have explained this better than I</a> (<a href="//developer.mozilla.org/en-US/docs/CSS/font-size-adjust">and Mozilla has a nice explanation, too</a>), but in general, the value for font-size-adjust</code> is meant as a scale factor of the font’s EM square. When I used an <a href="http://www.cs.tut.fi/~jkorpela/x-height.html">online tool</a> to calculate my custom font’s font-size-adjust</code>, it came out to be .435. </p>

As that value represents the relative aspect ratio of a font, it is not very useful when trying to craft some math for a Compass function. So I came up with my own method.

The Solution

Calculate the difference between fonts

Find your font’s scale factor with a simple test: Put two span</code>s next to each other at the same font-size, and with the browser Inspector, adjust the custom font until both look similar in size. If you adjusted the custom font to 110px, the ratio we need will be 1.1. If you made it smaller, the ratio is .95. Get it?

Sample code to create a test (in SCSS syntax):

.wrapper {
    color: black;

    span {
        font-size: 100px;
    }
    .custom-font {
        font-family: $alt-font;
    }
    .arial {
        font-family: Arial, sans-serif;
    }
}

You don’t have to use my markup, but this is the basic idea. I put the small x’s next to each other so they were easy to compare:

<div class=”wrapper”>
    <span class="custom-font">Xx</span>
    <span class="arial">xX</span>
</div>

Then manually, with Firebug or the browser’s inspector, adjust the size of the .custom-font</code> wrapper until the two samples look to be of similar height.

Sample of matching x-heights

In my case, making the custom font 115px matched the x-height of Arial. As a scaling factor, the function I created uses 1.15, the decimal equivalent of 115%. This means that when the custom font is used, it needs to be 15% larger than the default font in order to look like it is the same size This was a much easier way for me to think about font-size-adjust</code> and what that value means.

The Compass @mixin

If you are using a tool like <a href="http://modernizr.com/download/">Modernizr</a> and your feature-detection test includes one for fontface</code>, implementing this SCSS is easy. What the function does is set the font-size, but if there is fontface</code> support, it sets another font-size and scales it by the font-size-adjust-value. (<a href="http://www.projectevolution.com/activity/compass-scss-tricks-supporting-intention-font-size-adjust#fn1">This assumes some other things as well, I know. Read my full post with footnotes here.</a>)

$base-font-size: 16px; 
$font-size-adjust-value: 1.15; 

@mixin fontface-adjust( $pixel, $base-size:$base-font-size, $adjust-value: $font-size-adjust-value ) {
    /* Set a default value just in case */
    @if $adjust-value == none {
        $adjust-value: 1; 
    }
    /* Get rid of units, esp. since we are converting to EMs */
    $pixel: clear-units($pixel); 
    $base-size: clear-units($base-size);

   /* Output of the function */
    font-size: #{$pixel / $base-size}em;
    .fontface &amp; {
        font-size: #{$pixel*$adjust-value / $base-size}em;
    }
}

The result is a normal size Arial for devices without fontface</code> support, and an adjusted font size for those that have fontface</code>, and, we assume, are using the custom font.

The final calculations being used in context</p>

I hope this helps those of you who are facing a similar problem, and wish that font-size-adjust</code> had wider support by browsers. Until it has wider acceptance – once again – Compass and SCSS to the rescue (and Modernizr, too)!


Feel free to borrow the “px2em” function that this new function is based upon. The best part about it is the way a new value for base-font-size can be passed when font-sizes have been nested. For example, I have an H1 with one font size, but I want to make a <span></code> inside of it smaller. I can pass the pixel value of my H1 as the new base-font-size for which to make the <span></code>s EM calculation. </p>

@mixin px2em( $pixel, $base-size:$base-font-size ) {
    /* Remove units from the input for cleaner math */
    $pixel: clear-units($pixel); 
    $base-size: clear-units($base-size);
    @return #{$pixel / $base-size}em;
}

Example usage with EM-value nesting:

h1 {
    /* The default $base-font-size is used here */
    font-size: px2em( 24px );

    span {
        /* Context has changed because of the way EM values are inherited. 
        * I now need to scale based upon the size of the H1 */
        font-size: px2em( 14px, 24px ); 
    } 
}