Saturday, February 19, 2011

Google Web Fonts Flash of Unstyled Text (FOUT) Problem with wf-active



I decided to use a font off of Google Web Fonts but quickly ran into the FOUT (Flash of Unstyled Text) in Firefox. On the Web Fonts page, when you click on "use this font", the basic instructions tell you to put in a link to a stylesheet and then just use the new font family in your CSS. With that approach Firefox will first display the text in a native font, and then replace it with the new font once it's downloaded. So you get the FOUT.

So back to the Web Fonts page and on the "use this font" page towards the bottom there's a link for Advanced Techniques. You'll then see a link to the WebFont loader documentation. At first glance it looks like all you need to do is use their script and put the following type of styles in your stylesheet:
.wf-loading h1 {
        font-family: serif
      }
      .wf-inactive h1 {
        font-family: serif
      }
      .wf-active h1 {
        font-family: 'Meddon', serif
      }

The wf-loading, wf-inactive, and wf-active classes are added to your document <html> tag by Google's script at various points in time to reflect the state of what's happening with the font download. With that in mind I tried this:
.wf-loading h1 {
        font-family: serif;
      }
      .wf-inactive h1 {
        font-family: serif;
      }
      .wf-active h1 {
        font-family: 'Meddon', serif;
        visibility: visible;
      }
      h1 {
        visibility: hidden;
      }

The idea is that the h1's will initially be hidden and will only change to visible once the wf-active class is added to the html tag. It seemed that this should work fine, but it didn't. I'm not sure if this issue is specific to Blogger or not, but what I found is that I still get the FOUT. It's as if the Google script is adding wf-active class too soon, before the font is really ready.

In the comments, there's some confusion over the "visibility" property. Please check out Sitepoint's reference on the subject.


BACK TO THE DRAWING BOARD


So I went back to the WebFont loader documentation and dug a little deeper. The WebFont loader can be configured to invoke callback functions that you provide. One of the events that you can set a callback on is "active" - meaning that the font is loaded. I decided to try using this callback to make my text visible, so I changed the stylesheet to look like this:
.wf-loading h1 {
        font-family: serif;
      }
      .wf-inactive h1 {
        font-family: serif;
      }
      .wf-active h1 {
        font-family: 'Meddon', serif;
      }
      h1 {
        visibility: hidden;
      }

Notice that I no longer have visibility: visible in the wf-active rule. I'm now going to take care of making it visible in the active callback. Here's my first attempt at setting the callback function as part of the WebFontConfig object:
<script type='text/javascript'>
  WebFontConfig = {
    google: { families: [ 'Meddon' ] },
    active: function() {
      $('h1').css({'visibility':'visible';});
    }
  };
</script>

So all I'm saying here is: when the font goes 'active', set the visibility of my h1's to visible (I'm using jQuery to access all the h1's). This almost worked. In fact it worked about 50% of the time, but half the time the page loaded and the h1 did not show up at all.

I eventually concluded that the problem occurs in cases where the font is downloaded, and the active callback is firing, before the document itself is fully downloaded. In those cases, setting the h1 visibility doesn't work because the h1 doesn't exist yet in the DOM. So, my second attempt, which so far has worked 100% of the time, looks like this:
<script type='text/javascript'>
  WebFontConfig = {
    google: { families: [ 'Meddon' ] },
    active: function() {
      $('h1').css({'visibility':'visible';});
      $(document).ready(function() {
        $('h1').css({'visibility':'visible';});
      });
    }
  };
</script>

What I've added is a callback to be executed when the document is ready using the usual jQuery approach (the 'ready' method). So now those cases where the document is still downloading when the font become active are covered.


6 comments:

Anthony said...

Thanks for the fix! I had given up on using Google fonts in my headers because to that flash. Now it works fine.

Anthony said...

By the way, the correct syntax is visibility: invisible, not hidden. You're thinking of display:hidden.

Ben said...

The real problem is that the loader doesn't add the .wf-loading class to the html tag until the loader has initialized, so even using the loader's callbacks won't be 100% effective.

What I did was hardcoded .wf-loading to my html tag so that the style comes through before the script has initialized. No extra javascript necessary.

CSSBakery said...

Ben, Thank you for sharing. I'd like to give that a try. Since writing the post, I first switched to Cufon and finally to Typekit. My post titles are "Myriad Pro" by Typekit.

Delivered said...

SOLID post, thank you for sharing!!

Anonymous said...

Been having this problem on blogger myself, but can't seem to make your solution work. But I'm not a web design person at all so I might be completely off.

I'm assuming the way to change the stylesheet is by writing in the "add custom css" (advanced section of the template designer), from within my own blog?

Post a Comment