Graceful Degradation For Non-Standard Web Fonts

An early design decision we made for Codio was to spruce things up a bit by using Museo-Slab and Museo-Sans for most of our text. Since these are non-web standard fonts and we didn’t want to deal with the hassle of licensing and embedding the fonts ourselves, we used Typekit. For those of you not familiar with the service, Typekit hosts free and commercial fonts and makes using non-web standard fonts as simple as selecting what fonts you want from their font library and adding a javascript snippet to your <head>. Although the code below assumes the use of Typekit, it should be fairly easy to modify if you’re not using it. You can then use the fonts in your css like any other web standard font, e.g

body {                  
  font-family: "museo-sans-1","museo-sans-2","Arial";            
}

Font problems solved right? Well, sort of…

Font-Smoothing

Some computers, namely older Windows XP computers or people who decided to disable it for whatever reason, have font-smoothing disabled. If font-smoothing is disabled, your non-web standard fonts will probably look jagged and terrible. For example, take a look at what the Codio landing page looks like without font-smoothing:

No_font_smoothing

So how do we correct for this? Zoltan Hawryluk describes a nice technique for detecting font-smoothing in the browser using a canvas hack. Using this technique, a css class called ‘hasFontSmoothing-true’ is added to the html element if font-smoothing is detected. So in our css we could do something like:

body {                  
  font-family: "Arial";            
}
html.hasFontSmoothing-true body {   
  font-family: "museo-sans-1","museo-sans-2","Arial"; 
}

In this case, if font-smoothing is detected the body text will use Museo-Sans, but otherwise it’ll gracefully degrade to Arial.

Improvements

We found two shortcomings with the original implementation. The first is that it does the font-smoothing check every time a page is loaded, and it waits for the DOM to load before adding ‘hasFontSmoothing-true’. This creates a strange flicker on each page load when the fonts are switched, which is really annoying. The simple solution was to just cache whether the browser supports font-smoothing in a cookie so we don’t need to wait for DOM readiness except for the first time.

Related to the first is that if the browser doesn’t support font-smoothing, there’s no point in downloading the custom fonts since this will cause a slight performance hit, and needlessly impact our Typekit quota. Using the cookie from before, all we do is check if its value was set to ‘false’, and if so, don’t include the Typekit javascript in our html. Unfortunately we couldn’t figure out a way to do this 100% client-side that was cross-browser, so we resorted to doing it server-side. In Django that looks something like this, but the logic should be simple enough to duplicate in other frameworks:

In a context processor:

def typekit(request):     
    USE_TYPEKIT = request.COOKIES.get('hasSmoothing') != 'false'     
    return {'USE_TYPEKIT': USE_TYPEKIT}

In <head>

{% if USE_TYPEKIT %} 
<script src="//use.typekit.com/jip5udy.js" type="text/javascript"></script> 
<script src="{{MEDIA_URL}}js/FontLoader.js" type="text/javascript"></script>
{% endif %}

The FontLoader.js code which does the font-smoothing check can be found on github here: https://gist.github.com/792786