Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flash of partially styled content on page load #1525

Closed
dysbulic opened this issue Feb 16, 2023 · 4 comments
Closed

Flash of partially styled content on page load #1525

dysbulic opened this issue Feb 16, 2023 · 4 comments
Labels
bug Something isn't working frontend Front end related issues / features high High Priority

Comments

@dysbulic
Copy link
Member

dysbulic commented Feb 16, 2023

What happened?

When pages first load there is a period of up to several seconds when the content of the page is only partially styled. Specifically the Chakra global styles are loaded, but the component styles aren't loaded until the page renders on the client.

What did you expect to happen?

The page to be fully styled on load.

How can we reproduce the problem (as minimally as possible)?

Load the page. To make it particularly obvious turn on network throttling in network developers tools.

@dysbulic dysbulic added bug Something isn't working frontend Front end related issues / features high High Priority labels Feb 16, 2023
@dysbulic
Copy link
Member Author

I posted the following in Next.js's Discord server:

I am using Next.js v12 for working on https://metagame.wtf. When the page loads, there is a period when partially styled content displays.

We are using the Chakra UI component library (which is Emotion-based). The partially styled content is because the global styles are included in the server rendered page, but the component-specific styles are only being rendered when the page loads.

The page is large and has dozens of components. My assumption is that the page takes too long to render on the server — the global styles are inserted early on, but the component ones take long enough to render that the process ends before they complete.

Is this a reasonable explanation? Is there anything I can do to remedy the situation?

@dysbulic
Copy link
Member Author

I tried the <CacheProvider> tag from @chakra-ui/next-js, but it apparently relies on the application using the app/ directory structure, because when I try to run the code I get:

@metafam/web: [0] error - ../design-system/dist/ds.js (10113:0) @ createCache
@metafam/web: [0] error - Error [ReferenceError]: document is not defined
@metafam/web: [0]   10112 |   if (key === "css") {
@metafam/web: [0] > 10113 |     var ssrStyles = document.querySelectorAll("style[data-emotion]:not([data-s])");
@metafam/web: [0]   10114 |     Array.prototype.forEach.call(ssrStyles, function(node2) {
@metafam/web: [0]   10115 |       var dataEmotionAttribute = node2.getAttribute("data-emotion");

document is not defined on the server side.

It's weird because the original code from node_modules/@emotion/cache/src/index.js seems to be:

  if (isBrowser && key === 'css') {
    const ssrStyles = document.querySelectorAll(
      `style[data-emotion]:not([data-s])`
    )

    // get SSRed styles out of the way of React's hydration
    // document.head is a safe place to move them to(though note document.head is not necessarily the last place they will be)
    // note this very very intentionally targets all style elements regardless of the key to ensure
    // that creating a cache works inside of render of a React component
    Array.prototype.forEach.call(ssrStyles, (node: HTMLStyleElement) => {
      // we want to only move elements which have a space in the data-emotion attribute value
      // because that indicates that it is an Emotion 11 server-side rendered style elements
      // while we will already ignore Emotion 11 client-side inserted styles because of the :not([data-s]) part in the selector
      // Emotion 10 client-side inserted styles did not have data-s (but importantly did not have a space in their data-emotion attributes)
      // so checking for the space ensures that loading Emotion 11 after Emotion 10 has inserted some styles
      // will not result in the Emotion 10 styles being destroyed
      const dataEmotionAttribute = ((node.getAttribute(
        'data-emotion'
      ): any): string)

The isBrowser seems to be getting stripped out which is sort of critical.

To prevent Vite from being so smart, the component can be imported directly into the Next.js app rather than the design system.

@dysbulic
Copy link
Member Author

So, neither <CacheProvider> nor @emotion/server worked to end the FOUC.

The documentation for CacheProvider suggests that it useServerInsertedHTML only runs once and it is before rendering is complete.

One option is to upgrade to the app/ directory. I'll list that as an option in #1579.

@dysbulic
Copy link
Member Author

According to The Future of Chakra UI from March 2023, Chakra's biggest complaint currently is the CSS-in-JS setup that is causing our FOUC.

Their solution is to switch to a styleless component library called Ark & a program that will extract & compile the styles at build time called Panda CSS.

Supposedly the transition will begin in earnest once Panda CSS is released for production.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working frontend Front end related issues / features high High Priority
Projects
Status: Done
Development

No branches or pull requests

2 participants