Prevent FOUC in astro

When I am working on my own personal site(yes the one you are viewing now š¤£) using astro + tailwind plugin, I see a flashing on unstyled HTML. As I am using a free plan on netlify, the network latency makes the duration of the flash noticeably longš¤¦āāļø. To have a better UX, I have to find a way to solve it.
Root cause
Turns out the root cause is pretty simple:
browser first loads the index.html
after parsing the html, browser knows the site needs some additional .css files
browser renders index.html
browser fires css files request
browser combines the .css and DOM to make the rendering styled
Clearly, the flash happens from step 3 to step 5.
General solution
To solve the flash of unstyled content(a.k.a. FOUC), various tricks can be used, but the general ideas are the same: hide the rendering in step 3 and only make it visible after step 5. Here, I will introduce the simplest method, which only requires CSS and no JS is needed.
The idea is like this:
Add an inline css rule in index.html with
visibility: hidden;In the separate css file, change the rule to
visibility: visible;
Astro way to solve
To do this in astro, we can use the style directives. Add the following code in your root layout astro file:
<style is:inline>
body {
visibility: hidden;
opacity: 0;
}
</style>
<style is:global>
body {
visibility: visible;
opacity: 1;
transition: visibility 0.2s linear, opacity 0.2s linear;
}
</style>
PS: Opacity in here is for transition, which makes the website a little bit smoother.
In the code snippet, all the css rules under is:inline will be bundled in the html file, and is:global will be extracted to a separate css file. This will make the browser renders html in hidden first, and then load the css file and our content gets visible.
Inline? Or not inline?
You may ask, why don't we put all the styles in is:inline?
The short answer is: I am using tailwind plugin and it compiles the style in css module so I have no choice.
The long answer is: you should not. If all our css goes into html file, the file will be very big, making it longer to download. If you modular our css files into chunks, the loading time can be reduced. Only containing critical css rules inline, and passing all the heavy massive rules to a separate file would be the optimal way in balancing both styling and UX.
Final words
As SPA + CSS in JS dominated the market for a while, this kind of ancient problem seems to be disappear for a while. As server side rendering starts to catch(or we should say re-catch) people's eyes, ancient problem returns. For me this is a very interesting experience, as most of the discussion related to FOUC are very old, but it works on the latest cutting-edge framework. It reminds me that knowledge is not depend on time. The Oldest thing doesn't mean outdated.
Hope you enjoy this article. š