Fixing the 'Blank Text' Problem

In cases where textual content is loaded before downloadable fonts are available, user agents may render text as it would be rendered if downloadable font resources are not available or they may render text transparently with fallback fonts to avoid a flash of text using a fallback font - Font loading guidelines.

The ambiguity and lack of developer override in above spec language is a big gap and a performance problem. First, the ambiguity leaves us with inconsistent behavior across different browsers, and second, the lack of developer override means that we are either rendering content that should be blocked, or unnecessarily blocking rendering where a fallback would have been acceptable. There isn't a single strategy that works best in all cases.

Let's quantify the problem

How often does the above algorithm get invoked? What's the delta between the time the browser was first ready to render text and the font became available? Speaking of which, how long does it typically take the font download to complete? Can we just initiate the font fetch earlier to solve the problem?

As it happens, Chrome already tracks the necessary metrics to answer all of the above. Open a new tab and head to chrome://histograms to inspect the metrics (for the curious, check out histograms.xml in Chromium source) for your profile and navigation history. The specific metrics we are interested in are:

  • WebFont.HadBlankText: count of times text rendering was blocked.
  • WebFont.BlankTextShownTime: duration of blank text due to blocked rendering.
  • WebFont.DownloadTime.*: time to fetch the font, segmented by filesize.
  • PLT.NT_Request: time to first response byte (TTFB).

Text rendering performance on Chrome for Android

Inspecting your own histograms will, undoubtedly, reveal some interesting insights. However, is your profile data representative of the global population? Chrome aggregates anonymized usage statistics from opted-in users to help the engineering team improve Chrome's features and performance, and I've pulled the same global metrics for Chrome for Android. Let's take a look...

50th 75th 95th
WebFont.DownloadTime.0.Under10KB ~400 ms ~750 ms ~2300 ms
WebFont.DownloadTime.1.10KBTo50KB ~500 ms ~900 ms ~2600 ms
WebFont.DownloadTime.2.50KBTo100KB ~600 ms ~1100 ms ~3800 ms
WebFont.DownloadTime.3.100KBTo1MB ~800 ms ~1500 ms ~5000 ms
WebFont.BlankTextShownTime ~350 ms ~750 ms ~2300 ms
PLT.NT_Request ~150 ms ~380 ms ~1300 ms
No blank text Had blank text
WebFont.HadBlankText ~71% ~29%

29% of page loads on Chrome for Android displayed blank text: the user agent knew the text it needed to paint, but was blocked from doing so due to the unavailable font resource. In the median case the blank text time was ~350 ms, ~750 ms for the 75th percentile, and a scary ~2300 ms for the 95th.

Looking at the font download times, it is also clear that even the smallest fonts (<10KB) can take multiple seconds to complete. Further, the time to fetch the font is significantly higher than the time to the first HTML response byte (see PLT.NT_Request) that may contain text that can be rendered. As a result, even if we were able to start the font fetch in parallel with the HTML request, there are still many cases where we would have to block text rendering. More realistically, the font fetch would be delayed until we know it is required, which means waiting for the HTML response, building the DOM, and resolving styles, all of which defer text rendering even further.

Developers need control of the text rendering strategy

As the above data illustrates, fetching the font sooner and optimizing the resource filesize are both important but not sufficient to eliminate the "blank text problem". The network fetch may take a while, and we can't control that.

That said, knowing this, we can provide the necessary controls to developers to specify the desired text rendering strategy: there are cases where using a fallback is a valid strategy, and there are cases when rendering should be blocked. Both strategies are valid and can coexist on the same page depending on the content being rendered.

In short, text is almost always the single most important asset on the page, and we need to give developers control over how and when it's rendered. The CSS font rendering proposal should, I hope, resolve this.

Ilya GrigorikIlya Grigorik is a web ecosystem engineer, author of High Performance Browser Networking (O'Reilly), and Principal Engineer at Shopify — follow on Twitter.