Preloading @font-face fonts?
Asked Answered
F

16

151

Is it possible to preload or otherwise cache @font-face fonts, most likely with javascript, before the page loads so you don't get that ugly jump when the page finally does load?

Fettle answered 25/8, 2009 at 20:35 Comment(4)
Can't you specify height/line-height to avoid jump effect?Artillery
good place to start css-tricks.com/fout-foit-foftMil
developer.mozilla.org/en-US/docs/Web/HTML/Preloading_contentTman
https://mcmap.net/q/160248/-preloading-fonts-in-chrome-with-39-preload-39-link-directiveSolicitude
C
4

This answer is no longer up to date

Please refer to this updated answer: https://mcmap.net/q/157051/-preloading-font-face-fonts


Deprecated answer

I'm not aware of any current technique to avoid the flicker as the font loads, however you can minimize it by sending proper cache headers for your font and making sure that that request goes through as quickly as possible.

Claud answered 25/8, 2009 at 20:43 Comment(0)
T
99

Since 2017 you have preload

MDN: The preload value of the element's rel attribute allows you to write declarative fetch requests in your HTML , specifying resources that your pages will need very soon after loading, which you therefore want to start preloading early in the lifecycle of a page load, before the browser's main rendering machinery kicks in. This ensures that they are made available earlier and are less likely to block the page's first render, leading to performance improvements.

<link rel="preload" href="/fonts/myfont.eot" as="font" crossorigin="anonymous" />
<link rel="preload" href="/fonts/mywofffont.woff2" as="font" type="font/woff2" crossorigin>

Always check browser compatibility.

It is most useful for font preloading (not waiting for the browser to find it in some CSS). You can also preload some logos, icons and scripts.

Tman answered 19/10, 2017 at 12:55 Comment(6)
crossorigin is required even if the font is loaded from the same origin. Also good to provide a type hint.Counterattack
@IlpoOksanen added it nowTman
but how to assign font family name to the loaded font?Enhance
@DonDilanga I think this is something you must do via CSSTman
Works perfectly on Chrome 91, Safari 14, Firefox 89 & Opera 77!Atlantic
@DonDilanga you only fetch the resource; when the browser stumbles into the @font-face declaration, then it'll know it already has the resource.Strongarm
C
54

A simple technique is to put this somewhere in your index:

<div class="font_preload" style="opacity: 0">
    <span style="font-family: 'myfontface#1font-family', Arial, sans-serif;"></span>
    <span style="font-family: 'myfontface#2font-family', Arial, sans-serif;"></span>
    ...
</div>

Tested on Chrome 34, Safari 7 and FF 29 and IE 11

Chaste answered 16/5, 2014 at 14:48 Comment(3)
This worked perfectly in my situation to get fonts preloaded for use in fabricjs. Thanks.Adan
This works wonders in my use case (which can be arbitrarily weird when using web technologies for print): I’m trying to use a CSS font and set text in a box, but if the box overflows, I can slightly adjust the font size or letter spacing until it fits. But this can be automated: choose a minimum and a maximum letter spacing letter spacing and do a binary search between them for a decent value with which the text just about fits. But this requires requestAnimationFrame and maybe setTimeouts and a pre-rendered font! This does the trick. Surprising that the <span>s can be left empty.Clannish
But I’d strongly recommend using role="none presentation" for accessibility reasons and user-select: none; pointer-events: none; so that there’s no chance of interference with user events. Maybe even position: absolute; top: 0; transform: translateY(-100%);.Clannish
J
28

Avoid FOIT: Flash Of Invisible Text

A first step, for sure, is pre-loading the font in HTML:

<link rel="preload" href="pacifico.woff2" as="font" crossorigin="anonymous">

Please, note that fonts are always pre-loaded with cross-origin resource sharing (CORS) enabled, even though the font resides on the same server:

When preloading resources that are fetched with CORS enabled (e.g. fetch(), XMLHttpRequest or fonts), special care needs to be taken to setting the crossorigin attribute on your element. The attribute needs to be set to match the resource's CORS and credentials mode, even when the fetch is not cross-origin.

Hence, the crossorigin="anonymous" attribute is absolutely necessary.

The same cannot be said about the optional type="MIME-type" attribute. There is much discordance between browsers and institutions about what MIME-type fonts should be. If the wrong type is stated for a certain browser, the font file will not be pre-loaded. Therefore, it is better to refrain from using the type="MIME-type" HTML attribute all together.

Then, there is what the cool kids call FOIT; the flash of invisible text. In modern browsers, this FOIT can easily be avoided by adding the font-display: swap; property to the @font-face CSS declaration.

@font-face {
  font-family: 'Pacifico';
  font-style: normal;
  font-weight: 400;
  src: local('Pacifico Regular'), local('Pacifico-Regular'), url(pacifico.woff2) format('woff2');
  font-display: swap;
}
Joiejoin answered 21/3, 2021 at 23:18 Comment(3)
No need to look further. The definite answer here.Despatch
You wrote href="pacifico.woff2" but what if I want to store the data inside data:application/x-font-woff instead of external file?Dilate
Thank you for explaining the crossorigin="anonymous" bitGrady
S
24

There are a few techniques for "preloading" here: http://paulirish.com/2009/fighting-the-font-face-fout/

Mostly tricking the browser into downloading the file as fast as possible..

You can also deliver it as a data-uri, which helps a lot. and also you could hide the page content and show it when its ready.

Seoul answered 24/4, 2010 at 18:19 Comment(1)
Sorry, to dig this up, but I suspect I'm not understanding something. The tips on the blog post seem to be about hiding text while the font loads, but what if I just want get e.g. Chrome to load it ASAP and not when it encounters some text with that font? Is my best option a hidden div in the <head>?Aldridge
T
24

Your head should include the preload rel as follows:

<head>
    ...
    <link rel="preload" as="font" href="/somefolder/font-one.woff2">
    <link rel="preload" as="font" href="/somefolder/font-two.woff2">
</head>

This way woff2 will be preloaded by browsers that support preload, and all the fallback formats will load as they normally do.
And your css font face should look similar to to this

@font-face {
    font-family: FontOne;
    src: url(../somefolder/font-one.eot);
    src: url(../somefolder/font-one.eot?#iefix) format('embedded-opentype'),
    url(../somefolder/font-one.woff2) format('woff2'), //Will be preloaded
    url(../somefolder/font-one.woff) format('woff'),
    url(../somefolder/font-one.ttf)  format('truetype'),
    url(../somefolder/font-one.svg#svgFontName) format('svg'); 
}
@font-face {
    font-family: FontTwo;
    src: url(../somefolder/font-two.eot);
    src: url(../somefolder/font-two.eot?#iefix) format('embedded-opentype'),
    url(../somefolder/font-two.woff2) format('woff2'), //Will be preloaded
    url(../somefolder/font-two.woff) format('woff'),
    url(../somefolder/font-two.ttf)  format('truetype'),
    url(../somefolder/font-two.svg#svgFontName) format('svg');
}
Tibbitts answered 9/4, 2019 at 12:21 Comment(3)
It's good to add the following attributes type="font/woff2" and crossorigin to <link> to prevent browser errors. Otherwise this was the best answer for my case.Cassiopeia
When I try this, the font will be loaded twice. Once very early for the link with preload and a second time for the @font-face decleration.Narcotize
Try to add "crossOrigin" in your link, then it will load only once.Mesomorph
C
4

This answer is no longer up to date

Please refer to this updated answer: https://mcmap.net/q/157051/-preloading-font-face-fonts


Deprecated answer

I'm not aware of any current technique to avoid the flicker as the font loads, however you can minimize it by sending proper cache headers for your font and making sure that that request goes through as quickly as possible.

Claud answered 25/8, 2009 at 20:43 Comment(0)
O
4

Proper font pre-loading is a big hole in the HTML5 spec. I've gone through all of this stuff and the most reliable solution I've found is to use Font.js:

http://pomax.nihongoresources.com/pages/Font.js/

You can use it to load fonts using the same API you use to load images

var anyFont = new Font();
anyFont.src = "fonts/fileName.otf";
anyFont.onload = function () {
  console.log("font loaded");
}

It's much simpler and more lightweight than Google's hulking Webfont Loader

Here's the github repo for Font.js:

https://github.com/Pomax/Font.js

Odessaodetta answered 8/12, 2013 at 17:47 Comment(0)
T
4

Via Google's webfontloader

var fontDownloadCount = 0;
WebFont.load({
    custom: {
        families: ['fontfamily1', 'fontfamily2']
    },
    fontinactive: function() {
        fontDownloadCount++;
        if (fontDownloadCount == 2) {
            // all fonts have been loaded and now you can do what you want
        }
    }
});
Torry answered 24/6, 2015 at 3:53 Comment(3)
The guy above you gave the exact same answer 2 years before you.. why did you bother writing it again? I'm curiousWillin
My answer just gives a code snippet which people can use to load multiple fonts using webfontloader. The previous answer gives a nice introduction to webfontloader, but does not contain any code snippet.Torry
You should have edited it instead of repeating, and adding a code example. it's very confusing and waste of scroll to have almost identical answers repeating in questions.Willin
D
3

i did this by adding some letter in my main document and made it transparent and assigned the font that I wanted to load.

e.g.

<p>normal text from within page here and then followed by:
<span style="font-family:'Arial Rounded Bold'; color:transparent;">t</span>
</p>
Damian answered 14/1, 2013 at 3:35 Comment(0)
E
3

As I found the best way is doing is preloading a stylesheet that contains the font face, and then let browser to load it automatically. I used the font-face in other locations (in the html page), but then I could observe the font changing effect briefly.

<link href="fonts.css?family=Open+Sans" rel="preload stylesheet" as="style">

then in the font.css file, specify as following.

@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans Regular'), local('OpenSans-Regular'),
       url('open-sans-v16-latin-regular.woff2') format('woff2'); /*  Super Modern Browsers */
}

You can't assign a name to fonts when it's preloaded through link tag (correct me if I was wrong I couldn't find a way yet), and thus you have to use font-face to assign the name to the font. Even though it's possible to load a font through link tag, it's not recommended as you can't assign a name to the font with it. Without a name as with font-face, you won't be able to use it anywhere in the web page. According to gtmetrix, style sheet loads at the beginning, then rest of the scripts/style by order, then the font before dom is loaded, and therefore you don't see font changing effect.

Enhance answered 6/4, 2019 at 18:48 Comment(1)
I used this solution and tbh Chrome's Lighthouse is still saying these fonts should be preloaded as if it didn't recognise they are. I am going to replace it with Andrei's solution and see if there is any difference.Smoko
S
2

This should solve your problem.

To answer your initial question: yes you can. Only Gecko and WebKit browsers support it currently though.
You just need to add link tags in your head:

<link rel="prefetch" href="pathto/font">
<link rel="prerender" href="pathto/page">
Stephanystephen answered 13/1, 2010 at 17:45 Comment(4)
You should be careful with prerendering stuff on your page. It’s not the same as prefetching.Etam
why prerender and not preload ? it's a font, not an HTML file, there's nothing to render about itWillin
How to do it in CSS of @font-face?Dilate
@Willin sorry if that wasn't clear but these are two different methods. One is specific (prefetch only the font) and the other general (i.e. it will fetch the resources of that page in advance, fonts included). rel="prerender" has PROs (fetch several fonts at once) and CONs (fetch all resources. with caveats).Stephanystephen
S
2

Use the standard CSS Font Loading API.

Wait for (all) the fonts to load, and then show your content:

document.fonts.ready.then((fontFaceSet) => {
    console.log(fontFaceSet.size, 'FontFaces loaded.');
    document.getElementById('waitScreen').style.display = 'none';
});

Demo CodePen.

Supermarket answered 19/11, 2017 at 10:0 Comment(1)
This is now very widely supported: Font Loading API. More so than font-display: font-displayAcidify
F
0

Recently I was working on a game compatible with CocoonJS with DOM limited to the canvas element - here is my approach:

Using fillText with a font that has not been loaded yet will execute properly but with no visual feedback - so the canvas plane will stay intact - all you have to do is periodically check the canvas for any changes (for example looping through getImageData searching for any non transparent pixel) that will happen when the font loads properly.

I have explained this technique a little bit more in my recent article http://rezoner.net/preloading-font-face-using-canvas,686

Flagship answered 3/2, 2013 at 19:4 Comment(0)
D
0

Google has a nice library for this: https://developers.google.com/webfonts/docs/webfont_loader You can use almost any fonts and the lib will add classes to the html tag.

It even gives you javascript events on when certrain fonts are loaded and active!

Don't forget to serve your fontfiles gzipped! it will certainly speed things up!

Dannettedanni answered 7/3, 2013 at 13:30 Comment(0)
N
0

Finding the href to put in the link tag is the hard part, I explained it in detail in this article 🙂

Nessie answered 22/10, 2022 at 6:32 Comment(0)
D
0

You can use document.fonts like so

// Wait for all fonts to be loaded
document.fonts.ready.then(() => {
  // Execute your script here
  console.log('Custom font has been loaded');
});

https://developer.mozilla.org/en-US/docs/Web/API/Document/fonts

Defraud answered 5/4, 2023 at 7:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.