Avoid flash of invisible text

Katie Hempenius
Katie Hempenius

This code lab shows you how to display text immediately using Font Face Observer.

Add Font Face Observer

Font Face Observer is a script that detects when a font loads. The fontfaceobserver.js file has already been saved to the project directory, so you don't need to add it separately. However, you do need to add a script tag for it.

  • Click Remix to Edit to make the project editable.
  • Add a script tag for fontfaceobserver.js to index.html:
  <div class="text">Some text.</div>
  <script src="fontfaceobserver.js" type="text/javascript"></script>
</body>

Use Font Face Observer

Create Observers

Create an observer for each font family that it is used on the page.

  • Add the following script after the fontfaceobserver.js script. This creates observers for the "Pacifico" and "Roboto" font families:
  <script src="fontfaceobserver.js" type="text/javascript"></script>
  <script type="text/javascript">
    const pacificoObserver = new FontFaceObserver('Pacifico');
    const robotoObserver = new FontFaceObserver('Roboto');
  </script>
<body>

If you're ever unsure what font face observers you need to create, just look for the font-family declarations in your CSS. Pass the font-family name of these declarations to FontFaceObserver(). There is no need to create a font observer for fallback fonts.

For example, if your CSS was:

font-family: "Times New Roman", Times, serif;

you would add FontFaceObserver('Times New Roman'). Times and serif are fallback fonts, so you would not need to declare FontFaceObservers for them.

Detect font load

The code for detecting a font load looks like this:

robotoObserver.load().then(function(){
  console.log("Hooray! Font loaded.");
});

robotoObserver.load() is a promise that resolves when the font loads.

The demo site uses two different fonts, so you need to use Promise.all() to wait until both fonts have loaded.

  • Add this promise to your script, right below the FontFaceObservers that you just declared:
Promise.all([
  pacificoObserver.load(),
  robotoObserver.load()
]).then(function(){
  /* Do things */
});

✔️Check-in

Your script should now look like this:

<script type="text/javascript">
const pacificoObserver = new FontFaceObserver('Pacifico');
const robotoObserver = new FontFaceObserver('Roboto');

Promise.all([
  pacificoObserver.load(),
  robotoObserver.load()
]).then(function(){
  /* Do things */
});
</script>

Apply fonts-loaded class

  • Replace the /* Do things */ comment in the script with this line:
document.documentElement.classList.add("fonts-loaded");

This adds the fonts-loaded class to the document's root element (the <html> tag) once both fonts have loaded.

✔️Check-in

Your completed script should look like this:

<script type="text/javascript">
  const pacificoObserver = new FontFaceObserver('Pacifico');
  const robotoObserver = new FontFaceObserver('Roboto');

  Promise.all([
    pacificoObserver.load(),
    robotoObserver.load()
  ]).then(function(){
    document.documentElement.className += " fonts-loaded";
  });
</script>

Update CSS

Your page should be styled to use a system font initially and custom fonts once the fonts-loaded class has been applied.

  • Update the CSS:
.header {
html.fonts-loaded .header {
  font-family: 'Pacifico', cursive;
}

.text
html.fonts-loaded .text {
  font-family: 'Roboto', sans-serif;
}

Verify

  • To preview the site, press View App. Then press Fullscreen fullscreen.

If the page looks like this, then you've successfully implemented Font Face Observer and gotten rid of the "Flash of Invisible Text."

A heading in a cursive font.