How to get font to load on first visit

I’m working on Info Sec course’s Multiplayer Game. Using the font that was already linked in the provided boilerplate, I’ve got it working as the font for my game header, but usually, the font doesn’t show when visiting the page for the first time. If you hit refresh it will then display properly, but leave the site, and then go back to it, the font won’t display properly again until you refresh or hit enter on the address bar again.

FIRST VISIT TO SITE:

AFTER HITTING REFRESH:

Problem occurs on multiple different browsers. Site is Node.js hosted locally through VSCode. Font is called and drawn by Canvas Context, and is linked in the site header for the index.html.

FONT: Googles Press Start 2P

In the head of index.html (I’ve tried moving this around):

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <link href="https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap" rel="stylesheet">
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="../public/style.css" type="text/css" />

At the bottom of that same index.html (I’ve tried moving this around):

  </body>
  <script src="../public/game.mjs" type="module"></script>
</html>

And then in the game.mjs module:

function drawHeader () {
    // Draw top header bar
    context.fillStyle = 'darkgrey';
    context.fillRect( 0, 0, width, header);

    // Draw the game title
    context.fillStyle = 'black';
    context.font = "24px 'Press Start 2P'";
    context.fillText ("TANK", 10, 35);
    context.fillText ("BATTLE", 10, 65)

    // Draw the menu header
    context.font = "16px 'Press Start 2P'";
    context.fillText ("Controls    Score     Rank", 200, 20);

(NOTE: this draw is called after connection is confirmed by DOMContentLoaded with the server, and the server has sent io.to(id).emit('Welcome') to the client in response to a new connection, and the client has received it with socket.on('Welcome'), then it calls this drawHeader function, so I know all the HTML elements are loaded.

THINGS I’VE TRIED:------------------------------------
-Moving the link tag around
-Moving the game.mjs script tag around
-Connecting a client, refreshing to display properly, and then connecting another didn’t work
-Putting font-family: 'Press Start 2P'; in the css file for the canvas element
-Put the below in the head… url pulled from googleapis Press Start 2P CSS file

<link rel="preload" href="https://fonts.gstatic.com/s/pressstart2p/v14/e3t4euO8T-267oIAQAu6jDQyK3nWivN04w.woff2" as="font" crossorigin="anonymous">

THINGS THAT MIGHT WORK: ---------------------------------------------
-Seen reference to some 3rd party Javascript font preloaders
-Wondering if delaring a new fontface or something in DOMContentLoaded would help
-Wondering if there is just a simple elegant solution that google is hiding from me
-Maybe it’s just an affect of hosting locally, and will go away when the project is uploaded to “replit” or “glitch”

Hoping someone has dealt with this and knows a good elegant fix, otherwise I may start playing with some 3rd party software, and may get as messy as making the page reload itself to simulate a page refresh.

1 Like

If you post a link to your full project code on GitHub, then we could take a look and test out a few things.

1 Like

Maybe try using FontFace


I would think the browser would be caching the font. So I’m not sure why it wouldn’t load when revisiting the same page.

1 Like

I created a repository… keep in mind its still a work inprogress.

1 Like

Well, that was one of my thoughts. I went ahead and tried it by adding the below to my page, but no luck, still doesn’t load at first until you refresh the page. For some reason the font family is “Press Start 2P” but I couldn’t get this to work until I tried just “Press Start”… tried changing it to just Press Start in other areas, but that made the font not work at all.

    const myfont = new FontFace('Press Start', 'url(https://fonts.gstatic.com/s/pressstart2p/v14/e3t4euO8T-267oIAQAu6jDQyK3nRivN04w.woff2)');
    document.fonts.add(myfont);
    myfont.load().then( () => {console.log("Font is loaded.")});

I know I didn’t put the rest of my code inside the .then statement, but that would require a bigger rewrite than I wanted to try to squeeze in this afternoon… wanted to finish other aspects of the project by this afternoon.

1 Like

It seems to work with the Fraunces family name.

const myfont = new FontFace(
  'Fraunces',
  'url(https://fonts.gstatic.com/s/fraunces/v26/6NUu8FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0K7iN7iQcIfJD58njU0oc7qv8.woff2)'
);
document.fonts.add(myfont);
myfont.load().then(() => {
  context.font = "20px 'Fraunces'";
  console.log('Font is loaded.');
});
1 Like

Thanks. I mean, the code worked, I was able to load the “Press Start” font, but it did not resolve the problem of the font not being displayed on the first load of the page… still had to refresh the page to get the font to display properly.

1 Like

Not sure if this helps to troubleshoot the issue, but also, I’ve have found that if I leave my client up, but disconnect the server(for instance, when I save changes and the server refreshes), when the game comes back up, the font is distorted like so:

Hitting refresh again restores it back to how it is supposed to be, but I can’t find any reason it would distort… I specify the font size and family before each draw, so its not a leftover setting, and I didn’t at all distort the context or anything. I even went as far as having the client detect the disconnect, and clear the game board, meaning when the server reconnected it should have rebuilt the game board like a new player joining, but still, font is distorted… definitely weird.

1 Like

I forgot I had also commented out the font loading in the HTML. I didn’t re-test it again with the other font name.

Edit: If I move the drawHeader call out of the DOMContentLoaded callback to just after it/below it, the header layout seems to work on the initial load.

1 Like

Hum, I just removed the drawHeader call from inside the socket call inside the DOMContentLoaded function, pasted it right below, and still first load didn’t show the font, but a page reload did.

I’m pretty much done with the game now minus a few extra things I might refine, and this is the only problem left to solve. Today I build a simple NodeJS app, which basically only consists of a canvas and attempts to draw with this font, and it too doesn’t load initially, but only after hitting refresh on the page. Strange. I’ve also since loaded my app to Replit and the problem remains there.

https://replit.com/@kinome79/boilerplate-project-secure-real-time-multiplayer-game

So I’m going to mess with it over the weekend and see if I can resolve it. It might be the font, although the sample game uses this font and doesn’t seem to have this issue. Might try a different font, but that would constitute a failure on my part of me being able to get this to work, lol. Below is the code for the simple site that also fails to load this font on its initial load, but works after hitting refresh.

1 Like

Oh, and thanks for the continued effort :slight_smile:

1 Like

Well, if anyone comes up with something for this let me know, but I believe I’ve resolved it to my satisfaction.

Tried about everything regarding preloading fonts using the simple test app, but no matter what I tried, the first canvas draw would be in a default font, not the “Press Start 2P”. Tried preloading with <link rel="preload"..., @font-face, new FontFace, <canvas style="font-fami..., and even made the h1 header font Press Start 2P, and while the header would always display in the correct font, the canvas still would initially draw with a default font. I even setTimeout for 5 seconds to give it way to much time to load, and still, first draw was the wrong font, so its not that the font isn’t loaded, its just not using it.

What I did find out was that if a wrote something, waited a few milliseconds and then wrote something else, the second thing I wrote would be the correct font on first load. If I wrote multiple things together it would all be incorrect, but if I wrote, waited, and wrote again, the second thing would be correct.

I poured through the code for the sample game at “https://secure-real-time-multiplayer-game.freecodecamp.rocks/” because it doesn’t seem to have the problem with this font, including analyzing packets to see if it loads the font differently or something, but network packets regarding fonts were identical to my app, and my app even says the font is cached in my browser even before loading the page… what I did realize though was that the sample game re-draws the header every frame… so that leads me to assume maybe the first draw is incorrect, but its quickly overwritten with the second frame. I don’t redraw my header because its static, rather just redrawing the score box and rank when needed. Leads to some fun skid marks on the bottom of the header if you scrape your tank against it.

So my conclusion is that the font loads, but for some reason the first write on canvas will not use it… and I have no clue why. How I’ve resolved it though, is when the page first loads, I write “Loading…” in the center of the canvas… that is now the first write… milliseconds later, my header is drawn, and now, as the second draw, it writes in the correct font.

Ugh, my fatique regarding this issue has outweight my curiousity, so I’m done scouring the web for answers. There are mentions of similar issues, with answers ranging to everything above, third party webfont loaders, and some other hacky ways to try to get it to load, but no here’s why, and here’s how to fix it. Thanks again guys for your time messing around with my code.

Ugh… did find something that worked after all said and done… for some reason any manner of preloading and waiting didn’t work, but if I put my first draw on canvas inside this:

document.fonts.ready.then( () => {
    drawTitle();
}

It draws correctly the first time… technically all that should do is wait for the fonts to finish loading, which time should have also done, but didn’t. I even manually loaded the font, and got a status output stating “font is loaded”, but that didn’t work… but this above did… go figure.

Haha, nevermind… the ready function worked in my sample app, but still the “Loading…” of my main app still writes in default font even though being inside the document.fonts.ready promise… Oh well.

Can you please push the code with the changes? Not sure why it isn’t working for you.

Here is a repo as well.

https://github.com/lasjorg/font-header-load-test

A few comments up I have a link to a Replit with my game, and a Github with simple tester app. I’ve updated both with changes.

So, the tester app, I fixed it by adding that document.fonts.ready.then() statement. You can see the problem if you run that app… if you take the fonts.ready stuff out in the public/scripts.mjs module and just call drawTitle() by itself, you’ll see that the Press Start font doesn’t load when you first go to the page… put it back and it works. In the index.html you’ll see I supposedy preloaded the font, and I had commented out the preloader js stuff, but neither of those worked.

That said, I’ve fixed the game kinda… I added that “Loading…” text. if you watch closely though, the Loading is written in default font instead of Press Start, even though I added the document.fonts.ready.then() statement to the Loading text in the public/game.mjs module. Refresh the screen and you’ll see the Loading… text flash by now with the Press Start. Not sure why it works on the tester app, but not in the game.

Checked your supplied code, curious if you got it working with the “Press Start 2P” font, because I had my code setup the same way and it still didn’t work (although I guess I didn’t comment out the html link to googles stylesheet). I did put your Fraunces font into the tester app, and it still wrote incorrectly for the first write.

With the “Loading…” text in there now I’m satisfied with the results… still curious if there is a bug in this font, or something else.

I don’t see any new commits on the multiplayer repo.

If you clone my repo down and run it does it work for you or not?


Fraunces is the same font at a higher weight. At least they look the same to me and both get loaded.

The fonts getting loaded
/* vietnamese */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/fraunces/v26/6NUu8FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0K7iN7iQcIfJD58njU0oc0qv86Rg.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/fraunces/v26/6NUu8FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0K7iN7iQcIfJD58njU0oc1qv86Rg.woff2) format('woff2');
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/fraunces/v26/6NUu8FyLNQOQZAnv9bYEvDiIdE9Ea92uemAk_WBq8U_9v0c2Wa0K7iN7iQcIfJD58njU0oc7qv8.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/pressstart2p/v14/e3t4euO8T-267oIAQAu6jDQyK3nYivN04w.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/pressstart2p/v14/e3t4euO8T-267oIAQAu6jDQyK3nRivN04w.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek */
@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/pressstart2p/v14/e3t4euO8T-267oIAQAu6jDQyK3nWivN04w.woff2) format('woff2');
  unicode-range: U+0370-03FF;
}
/* latin-ext */
@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/pressstart2p/v14/e3t4euO8T-267oIAQAu6jDQyK3nbivN04w.woff2) format('woff2');
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/pressstart2p/v14/e3t4euO8T-267oIAQAu6jDQyK3nVivM.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

Sorry, still not a github/replit ninja yet, I just duplicated my changes over to the Replit manually instead of pushing from local to git, then git to replit… I should probably get out of that habit and use the tools provided, if not just to get better at it. The replit is currently my likely-to-be-submitted version, as I resolved the header issue with the Loading pre-text and I want to start the next class tomorrow.

I did build a replit using your github, ran it, and see that it says “font loaded” but I was able to do that with my Press Start font too… what doesn’t work is even though it says its loaded, if you try to use it to write to the canvas, the first write will be in the default font, not the one you just loaded. I did try writing in your selected font, but it didn’t seem different from the original for me to tell. I did change your code back to Press Start 2P and it I’m not able to write in that font at all although the console.log does say the font is loaded. Since you commented out the HTML stylesheet stuff, I can’t write to canvas in either font with just that FontFace load.

Definitely appreciate the effort. Right now I’m gonna clean the project up and get it submitted hopefully tonight.