Fun with Web Fonts

Nerd alert - this is a pretty technical article about fonts and font loading in HTML5. For the folks that just want to use new fonts in Gliffy, here is a quick demo of where they are and how they work:

gliffy font

The Basics

Loading web fonts into a standard web page is easy, but if you need full control of when they render and how they load, it can be a fairly difficult task.

Google fonts is a great resource. For most developers, you'd select the font you want to use and they'd give you this handy stylesheet reference that you could use to incorporate the fonts into your site:

&lt;link href='<a href="http://fonts.googleapis.com/css?family=Open+Sans" rel="nofollow">http://fonts.googleapis.com/css?family=Open+Sans</a>' rel='stylesheet' type='text/css'&gt;

But for an editor like Gliffy we had to tackle some more difficult problems such as loading fonts dynamically and knowing when they are fully ready to render. We also needed to normalize the vertical spacing between lines so that text rendered uniformly across the major browsers.

Font Loading

Fonts can be big! If there are lots of unicode glyphs in a font definition, font files can exceed 1MB each. In order to ensure the best user experience with Gliffy, we didn't want to load every new web font by default, just the ones that were being used in the current document. We needed to know when fonts would actually be loaded and ready to render before applying font styling to our text.

A bit of background: when you dynamically load a script on a page, there is a fairly sane callback system that lets you know when a script is loaded. Here it is in JQuery (vanilla js takes just a few more lines):

$.getScript(  "myAwesomeJavascript.js" , function( data, textStatus, jqxhr ) {
    //do stuff after script load
});

But for fonts, there is nothing in the HTML5 spec that lets you know when fonts are fully loaded and ready to render. There is a hack to "try your best" to know whether a font is loaded. Here is the gist:

font metrics

So we went ahead and implemented that, but it was clear that there were lots of edge cases to handle. So rather than re-inventing the wheel, we chose to use the Typekit Web Font Loader. They implement something very similar to what I described above. They have lots of implementation shortcuts if you're linking to fonts hosted on Google, FontDeck or Fonts.com, but we chose to host the fonts on our server and use the "custom" loader. It works great, and hides the details of font loading from your project. Here's what our code looks like:

WebFont.load({
     custom: {
     families: [ 'our-font-name' ]
     },
     timeout: 5000 ,
     active:function(which){
         //do stuff when fonts are loaded.
     }
});

 

Font Subsets

So now we were able to dynamically load fonts and know when our users decided to select them from our editing tool. But there was another problem. How could we give a preview of the font without loading the whole thing?

letters

Thankfully, our friends at Google have already done the heavy lifting on this. Earlier I showed you this way of including fonts:

<link href= 'http://fonts.googleapis.com/css?family=Open+Sans'  rel= 'stylesheet'  type= 'text/css' >

But if you just want to load certain characters of a font, you can simply change the href to this

<link href= 'http://fonts.googleapis.com/css?family=Open+Sans&text=Hello%20World'  rel= 'stylesheet'  type= 'text/css' >

So, in our case we added text=Open%20Sans, so that we could load just the characters "O", "p", "e" "n", etc into our version of the font for the dropdown menu. See the optimizing requests segment of google's font guide for details.

Base 64 Encoding

It is pretty well known that if you are including dozens of tiny icons on your site, you should compile them into a sprite sheet instead of loading each of them individually. We currently use a python script called glue to achieve this. The reasoning is that each HTTP request takes time, and if you're only loading one large image instead of many small ones, you'll shave off valuable milliseconds off of page load.

In the previous section I noted that we load many small subsets of fonts for display within our font selection drop-down menu.

Screen Shot 2015-01-07 at 6.25.33 PM

In CSS, you can base64 encode any type of binary data. The technique is frequently used to store tiny images directly in the CSS code, but we chose to use this technique to store all of our small font subsets. This article describes the nitty gritty, and there are many online sites that will do the base64 encoding for you.

We integrated base64 encoding into our build process and the result looks something like this:

@font -face {
     font-family:  'RobotoPlaceholder' ;
     font-style: normal;
     font-weight:  400 ;
     src: url( "data:font/woff;base64,d09GRgABAAAAAAiMABAAAAAACrQ ..." ) format( 'woff' );
}

We've also uploaded the tool that we created for this process to Github.

Line Heights

We want diagrams that are created in Internet Explorer to look exactly the same when they are opened in Firefox and Chrome. Sadly, line heights for different fonts vary across browsers.

The entry for line-height:normal in the CSS 2.1 spec says the following:

line-height:normal Tells user agents to set the used value to a “reasonable” value based on the font of the element. The value has the same meaning as <number>. We recommend a used value for ‘normal’ between 1.0 to 1.2. The computed value is ‘normal’.

Ouch. Talk about ambiguous! Thankfully, Eric Meyer, wrote a pretty great article on the subject in 2008 and created a fantastic tool for analyzing line heights across browsers.

At Gliffy, we extended the tool to work properly with web-fonts, and we posted it on GitHub. Basically when we render fonts, we normalize each of the heights to the exact line height value that Google Chrome assigns based on line-height:normal. That way text looks uniform across browsers. Here is one of the tables for the Roboto font:

"Roboto" : {
     "9px" "1.333" ,
     "10px" "1.400" ,
     ...
     "110px" "1.327" ,
     "127px" "1.323"
}

Screen-Shot-2015-01-13-at-6.09.17-PM

 

Line Height Metrics (source)

For most web development, integrating web fonts is a quick and easy task, but if you want finer control over loading and rendering of the font in a realtime editing environment, some of the techniques in this article should take the guesswork out of getting it right.

We hope that the new fonts in Gliffy will help you to make your diagrams beautiful.  Try Gliffy for free today at https://www.gliffy.com!