Wait for fonts to load before rendering web page

CssFontsFont Face

Css Problem Overview


I'm using @font-face to embed fonts in my website. First the text renders as the system default, and then (once the font file has loaded presumably) the correct font renders a fraction of a second later. Is there a way to minimise/get rid of this delay, by delaying the page rendering until after fonts have loaded or similar.

Css Solutions


Solution 1 - Css

Since nobody mentioned that, I believe this question needs an update. The way I managed to solve the problem was using the "preload" option supported by modern browsers.

In case someone does not need to support old browsers.

<link rel="preload" href="assets/fonts/xxx.woff" as="font" type="font/woff" crossorigin>

some useful links with more details:

https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content http://www.bramstein.com/writing/preload-hints-for-web-fonts.html

Solution 2 - Css

Edit: The best approach is probably to base64 encode your fonts. This means your font will have to be loaded fully by the time your HTML is parsed and displayed. You can do this with font squirrel's webfont generator https://www.fontsquirrel.com/tools/webfont-generator by clicking "Expert" and then "base64 encode". This is how services like TypeKit work.


Original answer: Another way to detect if fonts are loaded would be using FontLoader https://github.com/smnh/FontLoader or by copying their strategy.

They bind to the scroll event in the browser, because when the font loads it will resize the text. It uses two containing divs (that will scroll when the height changes) and a separate fallback for IE.

An alternative is to check the DOM periodically with setInterval, but using javascript events is far faster and superior.

Obviously, you might do something like set the opacity of body to 0 and then display it in once the font loads.

Solution 3 - Css

This is down to how the browser behaves.

First off where is your @font declared? Is it inline to your HTML, declared in a CSS sheet on the page, or (hopefully) declared in an external CSS sheet?

If it is not in an external sheet, try moving it to one (this is better practice anyway usually).

If this doesn't help, you need to ask yourself is the fraction of a second difference really significantly detrimental to the user experience? If it is, then consider JavaScript, there are a few things you might be able to do, redirects, pauses etc, but these might actually be worse than the original problem. Worse for users, and worse to maintain.

This link might help:

http://paulirish.com/2009/fighting-the-font-face-fout/

Solution 4 - Css

Joni Korpi has a nice article on loading fonts before the rest of the page.

http://jonikorpi.com/a-smoother-page-load/

He also uses a loading.gif to alleviate the delay so users won't get frustrated.

Solution 5 - Css

This code works very well for me. It uses the Font Loading API which has good support among modern browsers.

<style>
  @font-face {
    font-family: 'DemoFont';
    font-style: normal;
    font-weight: 400;
    src: url("./fonts/DemoFont.eot");
    src: url("./fonts/DemoFont.woff2") format("woff2"),
    url("./fonts/DemoFont.woff") format("woff"),
    url("./fonts/DemoFont.ttf") format("truetype");
  }

  .font {
    font-family: 'DemoFont';
    color: transparent;
  }

  html.font-loaded .font {
    color: inherit; // Override `transparent` from .font
  }

</style>
<script>
  // Check if API exists
  if (document && document.fonts) {    
    // Do not block page loading
    setTimeout(function () {           
      document.fonts.load('16px "DemoFont"').then(() => {
        // Make font using elements visible
        document.documentElement.classList.add('font-loaded') 
      })
    }, 0)
  } else {
    // Fallback if API does not exist 
    document.documentElement.classList.add('font-loaded') 
  }
</script>

The trick is to set the CSS color to transparent for elements using the font. Once loaded this is reset by adding font-loaded class to <html> element.

Please replace DemoFont with something meaningful for your project to get it work.

Solution 6 - Css

I had a similar problem while rendering to an HTML canvas, and this was my solution. It's based on the FontFace API, and similar to Holtwicks approach. The key differences are that this is a generic approach and that it will work out-of-the-box for external fonts/stylesheets (e.g. google fonts).

A couple of notes; fonts.load( ... ) will happily resolve with an empty set of fonts if the font isn't known yet. Presumably, this happens if this code is called before the stylesheet declaring the font was added. I added a fonts.check(...) to overcome that.

This will let you await javascript execution until a font is available, so it won't work out of the box for 'normal' HTML content. You can combine this with Holtwicks answer above.

export async function waitForFontLoad(
    font: string,
    timeout = 1000,
    interval = 10
) {
    return new Promise((resolve, reject) => {
        // repeatedly poll check
        const poller = setInterval(async () => {
            try {
                await document.fonts.load(font);
            } catch (err) {
                reject(err);
            }
            if (document.fonts.check(font)) {
                clearInterval(poller);
                resolve(true);
            }
        }, interval);
        setTimeout(() => clearInterval(poller), timeout);
    });
}

Solution 7 - Css

Only IE loads first the font and then the rest of the page. The other browsers load things concurrently for a reason. Imagine that there's a problem with the server hosting the font or with the font downloading. You will hang your entire site until the font is loaded. On my opinion a flash of unstyled text is better than not seeing the site at all

Solution 8 - Css

Use https://github.com/typekit/webfontloader

and check the events in the configuration https://github.com/typekit/webfontloader#configuration

<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"></script>
<script>
    WebFont.load({
        custom: {
            families: [ "CustomFont1", "CustomFont2" ]
        },
        active: function() {
            //Render your page
        }
    });
</script>

Solution 9 - Css

You can use CSS font-display inside your @font-face. The keywords for all the available values are:

  • auto
  • block
  • swap
  • fallback
  • optional

Giulio Mainardi has written a nice article about all of them, and which you should use where on sitepoint.

You can read it here: https://www.sitepoint.com/css-font-display-future-font-rendering-web/?utm_source=frontendfocus&utm_medium=email

Solution 10 - Css

(function() {
		document.getElementsByTagName("html")[0].setAttribute("class","wf-loading")
		document.getElementsByTagName("html")[0].setAttribute("className","wf-loading")
	})();

use this method.. use with Webfont.js

Solution 11 - Css

Maybe something like this:

$("body").html("<img src='ajax-loader.gif' />");

Then when the page loads, replace body's content with the actual content and hopefully, fully rendered fonts, you may have to play around with this though...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionwheresrhysView Question on Stackoverflow
Solution 1 - CssThiago C. S VenturaView Answer on Stackoverflow
Solution 2 - CssRyan TaylorView Answer on Stackoverflow
Solution 3 - CssTom GullenView Answer on Stackoverflow
Solution 4 - CssdavecaveView Answer on Stackoverflow
Solution 5 - CssHoltwickView Answer on Stackoverflow
Solution 6 - CssFluffyView Answer on Stackoverflow
Solution 7 - CssnunopoloniaView Answer on Stackoverflow
Solution 8 - CssklodomaView Answer on Stackoverflow
Solution 9 - CssLiriannaView Answer on Stackoverflow
Solution 10 - CssNadilka PereraView Answer on Stackoverflow
Solution 11 - Cssbenhowdle89View Answer on Stackoverflow