Next.js: Unexpected onLoad attribute behaviour in next/head

Created on 16 May 2020  路  5Comments  路  Source: vercel/next.js

Bug report

Describe the bug

In my project raam I'm tying set "Inter" as my font by linking to a stylesheet from Google Fonts.

In Head (a component that extends next/head) I'm using:

<link rel="preconnect" href="https://fonts.gstatic.com/" crossOrigin="" />
<link
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
  rel="stylesheet"
/>

(note the preconnect to the actual font assets, then the display=swap which is intended to show the fallback font until the loaded font is swapped in)

When I then go to view the page (in Firefox particularly) I see a flash of unstyled/invisible text:
https://raam-git-chore-inter.joebell.now.sh/

Screenshots

ezgif-2-8ea6320f12f1

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Go to https://raam-git-chore-inter.joebell.now.sh/ (in Firefox where this is more visible)
  2. Hard reload and watch the behaviour of fonts

Expected behavior

The system font is seen first, and 'swapped' to Inter on load.

System information

  • OS: macOS
  • Browser (if applies): Firefox 75
  • Version of Next.js: 9.3.3
  • Version of Node.js: 13.8.0

Additional context

I appreciate there's a lot of variables here: Theme UI, Google Fonts, Now.sh, Next.js, but it would be good if we can figure out the root cause here for others using Next.js. If it's something that could be resolved by adding some documentation I'd be more than happy to do so.

Thanks again for all of the team's hard work on Next.js, it's a real pleasure to work with

Prior reading

Example

good first issue

Most helpful comment

As an update I've tested this new approach, which is a mix of font-loading performance suggestions I've found online:

<link
  rel="preload"
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
  as="style"
/>
<link
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
  rel="stylesheet"
  media="print"
  // // Next.js doesn't like this but it allows us to load CSS asynchronously
  // @ts-ignore
  onLoad="this.media='all'"
/>

| Before | After |
|--------|-------|
| Screenshot 2020-05-17 at 13 40 49 | Screenshot 2020-05-17 at 13 58 06 |

However a slight flash still remains and TypeScript doesn't like my onLoad="this.media='all'" as it doesn't accept string values. Am I doing this wrong or do I need to raise a PR to update types?

I have a hunch that something in next/head is changing after load on the client, but I'm not experienced enough to know what's happening under the hood to cause this FOUT.


Update #1 - I've tried fg-loadCSS but the same FOUT issue occurs. Whatever approach there is still a small FOUT.

All 5 comments

Did some testing on other devices: iPad OS and iOS have no issues. Seems like it only occurs on macOS but I can鈥檛 verify Windows. I've tried removing the Theme UI hook to see if this was the root, but it appears to make no difference.

As an update I've tested this new approach, which is a mix of font-loading performance suggestions I've found online:

<link
  rel="preload"
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
  as="style"
/>
<link
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
  rel="stylesheet"
  media="print"
  // // Next.js doesn't like this but it allows us to load CSS asynchronously
  // @ts-ignore
  onLoad="this.media='all'"
/>

| Before | After |
|--------|-------|
| Screenshot 2020-05-17 at 13 40 49 | Screenshot 2020-05-17 at 13 58 06 |

However a slight flash still remains and TypeScript doesn't like my onLoad="this.media='all'" as it doesn't accept string values. Am I doing this wrong or do I need to raise a PR to update types?

I have a hunch that something in next/head is changing after load on the client, but I'm not experienced enough to know what's happening under the hood to cause this FOUT.


Update #1 - I've tried fg-loadCSS but the same FOUT issue occurs. Whatever approach there is still a small FOUT.

After some further investigation with @csswizardry, we found that when JS is disabled the onload attribute is missing entirely:

Screenshot 2020-05-18 at 16 47 29

What's even stranger is once JS is enabled, this behaves as expected but moves further down the <head> element:

Screenshot 2020-05-18 at 16 48 03

This leads me to think next/head is rendering without onLoad on the server, then shuffling around things upon hydration

This leads me to think next/head is rendering without onLoad on the server, then shuffling around things upon hydration

onload is handled by React so I assume it's read as if it's a React event handler.

Thanks for getting back to me @timneutkens, I was just about to update this issue as I've managed to build a workaround solution in the meantime: next-google-fonts

I'd still prefer to use onload, but it seems fine for now

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jesselee34 picture jesselee34  路  3Comments

renatorib picture renatorib  路  3Comments

olifante picture olifante  路  3Comments

lixiaoyan picture lixiaoyan  路  3Comments

ghost picture ghost  路  3Comments