Font events: Using JavaScript callbacks

This is our fourth and final post in an ongoing series about using font events for better control over how web fonts load. Read the first post for an overview of font events, the second post for information on controlling the FOUT, and the third post for information on fallback fonts and styles.

In the past several posts in this series, we’ve discussed how to use Typekit font events in your CSS to control the FOUT and apply fallback fonts and styles. But there’s another aspect that we haven’t yet discussed: font events can be used via JavaScript callbacks as well.

Screenshot of the promo on the Typekit homepage fading in after fonts have loaded
Font event JavaScript callbacks in action on the Typekit homepage.

Why would you want to use font events in JavaScript? We’ve already discussed using font events in CSS to avoid the flash of unstyled text. However, if you have very large text set in a web font, such as in a module promoting a product, the sudden appearance of that text may be jarring. In this case, you may want to fade in the text gradually after the font is loaded (an effect that wouldn’t be appropriate for an entire page of body text). This is where font event JavaScript callbacks come in handy. In fact, we use font events and JavaScript to achieve a fade-in effect on the Typekit homepage.

The three main font events (loading, active, and inactive) are available in JavaScript via callback functions that you pass in when you call Typekit.load. Here's the generic example of setting up callback functions for each of these three font events:

<script type="text/javascript" src="http://use.typekit.com/xxxxxxx.js"></script>
<script type="text/javascript">
 try {
   Typekit.load({
     loading: function() {
       // Javascript to execute when fonts start loading
     },
     active: function() {
       // Javascript to execute when fonts become active
     },
     inactive: function() {
       // Javascript to execute when fonts become inactive
     }
   })
 } catch(e) {}
 </script>

Let's take a look at a simple example page that demonstrates one way to accomplish the fade in behavior using these JavaScript callbacks. Our example uses the jQuery JavaScript library to make things like DOM manipulation, hiding, and fading elements easy, but you could just as easily use another library. Here are the basic steps necessary to achieve this effect:

  1. As soon as the DOM is ready, hide the web fonts by applying visibility: hidden.
  2. Once the fonts have finished loading, remove visibility: hidden and fade in the text (using jQuery's .fadeIn).
  3. If the fonts don't load successfully, remove visibility: hidden. We can also apply fallback styles in CSS using the wf-inactive class (as we discussed in our previous post on fallback styles).

Time-lapse capture of the example page fade in Mac Firefox and Windows IE8
Time-lapse capture of the example page fade: Mac Firefox above, Windows IE8 below

Unfortunately, when you look at this example in Internet Explorer, you'll notice that there are some jagged black outlines around the edges of the characters as they fade in. This is because IE8 and below don't support CSS opacity, but instead use a proprietary filter. The upcoming release of IE9 will reportedly support CSS opacity and should address this issue. However, if we want to avoid these jagged outlines now, we need to make sure that browsers that don't support CSS opacity use an alternate effect, such as showing the text immediately. jQuery provides a handy jQuery.support.opacity property that we can use to test if a given browser supports CSS opacity.

Pulling it all together, here's the JavaScript code from the example page that loads jQuery, loads our kit, and then sets up the fade-in behavior (while avoiding that effect in browsers that don't support CSS opacity):

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script type="text/javascript" src="http://use.typekit.com/lmu3khn.js"></script>
<script type="text/javascript">
  (function() {
    $(document).ready(function() {
      // As soon as the DOM is ready, make the example invisible
      $('#example').css('visibility', 'hidden');
    });
    try {
      Typekit.load({
        active: function() {
          // As soon as the fonts are active, fade in the example
          // Don't fade in browsers that don't do proper opacity, like IE
          if (jQuery.support.opacity) {
            $('#example').css('visibility', 'visible').hide().fadeIn();
          } else {
            $('#example').css('visibility', 'visible');
          }
        },
        inactive: function() {
          // If the fonts are inactive, just show the example
          // You can apply fallback styles using the wf-inactive class in your CSS
          $('#example').css('visibility', 'visible');
        }
      })
    } catch(e) {}
  })();
</script>

Now we've progressively enhanced our page for browsers that support CSS opacity with a fade-in effect that makes the appearance of our web font less abrupt. Again, this type of effect is most appropriate for small amounts of large text, not for an entire page of body text. Typekit font events give you the control you need, allowing you to conditionally trigger CSS styles and JavaScript code as the fonts are loading.

This is the last post in our series on font events. If we missed covering an application of font events that you're interested in, let us know in the comments. And as always, you can email Typekit support with any questions. Thanks for tuning in!

6 Responses

  1. Dragos says:

    Awesome! Thx

  2. Thanks for making the load of webfonts smoother and for trying to improve your service every day.

  3. Edoardo says:

    Excellent! Will make use of it!

  4. Alan Houser says:

    Awesome sauce! This is what I was looking for. No-more jumpy text on each page-load.

  5. Theo says:

    Typekit is simply great!

  6. GrayGhost says:

    This would also be a great trick using the CSS3 animation and CSS3 Transition property.

Comments are closed.