typekit/webfontloader

Active firing too early on WebKit browsers

tandara98 opened this issue · 26 comments

On WebKit browsers (Chrome and Safari) under Windows when using custom module Webfont loader fires fontactive and active (the same holds for the wf-active class) before fonts become displayed and the page is laid out using loaded font metrics.

Do you have a sample page or test page that demonstrates this issue in action?

Ok, here is the definitive proof that fontactive is fired much earlier than it really should:

http://coocootz.hostzi.com/webfonts/debugger.html

I've inserted a listener component that checks every 50 milliseconds if the width of the menu element has changed. It is obvious that fontactive is fired before the font is loaded.

Moreover, by investigating page loading process using chrome developer tools, I figured out that fontactive is fired immediately after the request for the font file is sent, without waiting for the file to finish downloading.

Test shows that the width of the element applying a webfont is changed twice on webkit browsers! Webfont loader registers the first such change and fires active state. Apparently, that is the moment when the request for the font file is sent to the server. Font file is loaded and active only after the second width change.

I've experimented with font stacks, and this is what I've found out about the behavior of webkit browsers...

Both Chrome and Safari start by applying the first fallback font from the font stack.

Then, on the first width change, when apparently the request for the font file has been sent, they change the font differently. Safari's behavior is consistent and it changes the font to its own default font which is not in the font stack. This is apparently the font which would be used if there is no fallback font specified in the font stack (i.e. 'standard font' as specified in the browser preferences). On the other hand, if there is a generic family in the font stack (like "serif", "sans-serif", etc.), Chrome chooses to change the font to that one. If not, it behaves like Safari: it changes the font to the same default font as Safari.

Finally, on the second width change, they change the font to the one which just finished loading.

Interesting. Do you see the same problem if you load fonts from Google, Typekit, or one of the other modules, or is this only a problem with custom fonts?

(Also, your test case page appears to be down for "administrative review". Not sure what that means.)

I've tried loading fonts from Google, and there is no difference in behavior. I guess it is just the way webkit browsers handle the process of webfont loading: while the font file is being loaded, they switch to their own alternative.

(Sorry for the inconvenience with the web page accessibility. I think the problem arose because I turned off the automatic inclusion of the analytics code to my pages. It should not happen again.)

I also get this issue, here's a test page http://fonttest.theteamdigital.com/render-pattern/webfontloader.php

The first paragraph should hide until the font has loaded. The third should show until the font has loaded.

In Chrome the 3rd paragraph hides while the font loads as the 'active' class is added too early. Compare to Firefox where it works as expected.

Same deal for me. I'll try to come up with a legit example later.

Alright, finally ran into this one myself through a different avenue and tracked it down. It looks like Webkit browsers will briefly change the width of a web font before it actually renders (and even when the font is invalid and won't render) for a single check cycle. Something to do with how they render the fonts.

The solution I found is to wait for the font to render at a consistent width for two checks. I have a pull request out for this now, but I think it should address this issue as well: #32

Seen this too. When used with canvas, it doesn't just create a delay/flash, it means the text never gets written.

Demo:
http://jsfiddle.net/mqnuP/

This pull request is now merged into the latest version of the library, so if you're using the latest version, you should no longer see this issue.

Thanks <3

I still have this issue, even with the latest version.

benoitr007: Do you have a simple test case that demonstrates the problem you're having? If not, can you make one?

I just made one: http://www.benetonfilms.com/temp/webfont_loader_sample.html

But I also noticed the results are not always the same. In fact, it seems pretty random. Keep refreshing in Chrome, sometimes you will get this:

Document ready. DIV width = 193
Fonts loaded. DIV width = 171

The values should be the other way around, shouldn't they? For some reason, in FF, I get 193 and 202, respectively. Is it just me or something odd is going on?

Thanks!

You'll probably get more consistent results in Chrome if you use a new
incognito window (suppresses the existing cache). I got the same as you
twice just now, doing that.

On Mon, Sep 19, 2011 at 6:18 PM, benoitr007 <
reply@reply.github.com>wrote:

I just made one:
http://www.benetonfilms.com/temp/webfont_loader_sample.html

But I also noticed the results are not always the same. In fact, it seems
pretty random. Keep refreshing in Chrome, sometimes you will get this:

Document ready. DIV width = 193
Fonts loaded. DIV width = 171

The values should be the other way around, shouldn't they? For some reason,
in FF, I get 193 and 202, respectively. Is it just me or something odd is
going on?

Thanks!

Reply to this email directly or view it on GitHub:
#26 (comment)

The problem is I am using the active event to calculate a few things based on the width of DIV's that contain text, so I really need them to return the correct value, which is not the case right now.

Me too.

My workaround for this is to start polling the metrics, with the first poll
immediately after the active event fires.

On Mon, Sep 19, 2011 at 6:24 PM, benoitr007 <
reply@reply.github.com>wrote:

The problem is I am using the active event to calculate a few things based
on the width of DIV's that contain text, so I really need them to return the
correct value, which is not the case right now.

Reply to this email directly or view it on GitHub:
#26 (comment)

I think this issue should probably be reopened.

When the request is made to a font that does not yet exist in cache, the way WebKit handles FOUT hits (makes the text invisible while it's loading) and the text is still invisible when the active event is fired.

Try this test case in a fresh Chrome incognito mode: http://jsfiddle.net/9rJAj/2/

This is causing an issue with BigText where the text sizes incorrectly when the font is loaded using WebFont loader. See live at http://chrisnager.com/

There's currently a fix that should address this that we're working on in #38. The issue is due to an unfortunately web font loading behavior in Webkit-based browsers. I don't think we need to reopen this since we already have that pull open.

Cool, thanks!

Just FYI I checked the jsfiddle linked above and it's still broken. Should this be reopened?

The fix that went in was only for using Webfontloader with Google's service. Other services unfortunately still exhibit this behavior. We're going to have to totally rethink our font loading strategy in order to get around this webkit behavior, and so progress on this issue is currently on the backburner.

We already have another issue at #43 that documents this problem, so I don't think we should reopen this one as well.

One idea that may work is to create an Image() element and append the font url to its src. That way its possible to know when it failed loading and when its loaded (since browsers will not be able to render the image, but the font will be cached). The only problem is that I don't know if there's anyway to acquire @font-face declarations src attribute.

there is FOUT in chrome 24, check the fiddle for confirmation: http://jsfiddle.net/9rJAj/2/

Hi @waynehoover, I just checked your Fiddle, and I don't think it actually demonstrates what you want. A better way to test is to use the provided font event CSS classnames to hide the element until the fonts are done loading. I updated the fiddle to do that, and I don't see any FOUT: http://jsfiddle.net/9rJAj/9/

FOUT is not hidden by default when using webfontloader, but it does give you the tools to manage it yourself.