tl;dr; More experiments with different ways to lazy load CSS with and without web fonts. Keeping it simple is almost best but not good enough.
Go Straight to the Results
Visual comparison of 6 different solutions
Same visual but as a comparative video
Stare at that for a second or two. Note that some versions start rendering something earlier than others. Some lose some of their rendered content and goes blank. Some change look significantly more than once before the final rendered result. As expected they almost all take the same total time till the final thing is fully rendered with DOM and all CSS loaded.
What Each Experimental Version Does
A regular webapp straight out of the
./build directory built with Create React App. Blocking CSS, blocking JS and no attempts to show any minimal DOM stuff first.
Optimized Version 1
Inline CSS with basic stuff like background color and font color. CSS links are lazy loaded using tricks from loadCSS.
Optimized Version 2
defer on it to prevent render blockage.
Optimized Version 3
Not much of an optimization. More of a test. Takes the original version but moves the
<link rel="stylesheet" ... tags to just above the
</body> tag. So below the
Optimized Version 4
All custom web font loading removed. Bye bye "Lato" font-family. Yes you could argue that it looks worse but I still believe performance makes users more happy ultimately than prettiness (not true for all sites, e.g. a fashion web app).
Actually this version is copied from the Optimized version 1 but with the web fonts removed. The final winner in my opinion.
Optimized Version 5
Out of curiousity, let's remove the web fonts one more time but do it based on the Original. So no web fonts but CSS still render blocking.
So, Which Is Best?
I would say Optimized version 4. Remove the web font and do the
Also, Chrome is quite a popular browser after all and the first browser that supports
<link rel="preload" ...>. That means that when Chrome (and Opera 43 and Android Browser) parses the initial HTML and sees
<link rel="preload" href="foo.css"> it can immediately start downloading that file and probably start parsing it too (in parallel). The visual comparison I did here on WebPagetest used Chrome (on 3G Emerging Markets) so that gives the optimized versions above a slight advantage only for Chrome.
To really make your fancy single-page-app fly like greased lightning you should probably do two things:
Server-side render the HTML but perhaps do it in such a way that if your app depends on a lot of database data, skip that so you at least send a decent amount of HTML so when React/Angular/YouNameIt starts executing it doesn't have to do much DOM rendering and can just go straight to a loading message whilst it starts fetching the actual AJAX data that needs to be displayed. Or if it's a news article or blog post, include that in the server rendered HTML but let the client-side load other things like comments or a sidebar with related links.
bootstrap.min.css) to have all styles ready when the user starts clicking around on stuff.
Most important is the sites' functionality and value but hopefully these experiments have shown that you can get pretty good mileage from your standard build of a single-page-app without having to do too much tooling.