In-Lining CSS on First Page View

Greetings,

I was wondering what people’s thoughts are on doing this:

  • Inline ALL CSS on first page view (or until the user has it in their cache - can have an AJAX call to the server letting the server know this is complete)
  • On that same page view, have the last event that takes place (besides the AJAX call) download an external CSS stylesheet with the same CSS that was inlined so that it is cached for future calls
  • On future page views, serve the CSS as an async stylesheet in the HTML HEAD section (which should be cached at that point)

I was doing this just for CRITICAL CSS but I was having rendering above the fold issues that went away when I placed all css in the head inlined.

Initial thought on this procedure is that what if the user clears cache? Well, the cookie that stores the session variables (including the one that the ajax call would set) would be cleared. So what if the user clears cached images and files but not cookies? It would be rare but it could happen. However, since the CSS is async in the HTML HEAD, it would just download it again. Some people say it might defeat the purpose but it is rare that somebody would clear cache and then continue to use the website on that same visit. Future visits would have cookies expired.

How much critical CSS is too much CSS though to put in HTML HEAD as inline? At what point does this method become user un-friendly? Thoughts?

Sincerely,
Travis Walters

Depends on how big your CSS is.

It’s a fairly old technique that works well (I believe Yahoo was one of the first to do it ~8-10 years ago). You can generalize it by having a hidden iFrame that you load after onload that is used to cache critical resources and have that frame request set a cookie (including the version of the cached bundle). Then on page views if the cookie is present you don’t inline (or include the pre-caching code) and if the cookie is not present you do the inline hop.

As you mention, even in the case where the files are cleared but the cookies are not (rare) nothing breaks, it is just slower because it has to load the external resources like it would have if they weren’t inlined.

Hey There,

According to the Firefox Developer Console, the webpage is initially 125.90 KB on first load and about 31.98 KB on additional loads. The CSS is about 93.99 KB. I believe this console is showing the size of the request after it has been unzipped and extracted. The gzip size of the home page on initial load appears to be 25.7 KB and 5.8 KB on additional loads.

According to netindex, the average global download speed is 11.3 MBps, which corresponds to 11,300 KBps. Thus, 25.7 KB / 11,300 KBps = 0.00227 seconds or 2.27 milliseconds.

I have been doing my tests on a cable connection (5/1 Mbps = 625 kBps = 5000 Kbps) on your website. Thus, 25.7 KB / 5000 KBps = 0.0514 seconds or 5.14 milliseconds.

Initial Webpage Load:
Start Offset: 0.370 s
Initial Connection: 118 ms
SSL Negotiation: 252 ms
Time to First Byte: 332 ms
Content Download: 15 ms
Bytes In (downloaded): 25.7 KB
Bytes Out (uploaded): 0.3 KB

Additional Webpage Load:
Start Offset: 0.393 s
DNS Lookup: 3 ms
Initial Connection: 121 ms
SSL Negotiation: 263 ms
Time to First Byte: 145 ms
Content Download: ms
Bytes In (downloaded): 5.8 KB
Bytes Out (uploaded): 0.6 KB

Of course, my calculations are theoretical in a perfect world and actual results are a bit slower as indicated above.

Start Offset: 0.370 s and Initial Connection: 118 ms
I cannot do much about these unless I have a server closer to the user right?

SSL Negotiation: 252 ms
I don’t think my intermediate certificate is setup correctly at the moment so I expect this time to improve a bit. When I run some tests on your testing software, I can see that when SSL negotiations start, a request is made to startSSL.com. It is not apparently on all requests though but I think it might be happening behinds the scenes?

Time to First Byte: 332 ms vs Time to First Byte: 145 ms
I suppose the first TTFB could be up a bit because it establishes SESSION variables and sends a cookie to the user. I expect this value to increase when I do the actual ColdFusion programming behind the scenes.

Content Download: 15 ms
I do not think this will get much better. I pretty much send text and css during my webpage request and then load additional requests (images, javascript, etc) via AJAX. I was actually able to get a perfect score in the Google PageSpeed Insights tool by loading external resources such as AdSense scripts via AJAX. Advertisements should always be loaded last in my opinion anyway. I am all about user experience.

I was not even going to put ALL inline CSS in the HTML HEAD on initial load but there was a flicker that happened for about a tenth of a second and also the Insights tool showed what the screen looked like before AJAX was loaded so I decided to just include the CSS. From my results thus far, it does not seem to effect things too much.

I might even apply the technique I mentioned in the previous post to other elements on my website. Maybe I can pre-load some images via AJAX so that they appear right way when a user reaches the inner pages of my website. I might as well if the browser is idle and it does not effect anything at that point.

Patrick, do you think this is an outdated approach: I remember awhile back (a few years ago actually) that we had a discussion where using subdomains such as img1.example.com, img2.example.com, image3.example.com, etc may open up additional connections since some older browsers are limited to 2 connections per website. Do you think that is worth doing at this point in time or have we moved on to a point where the 2 connection limit does not apply anymore? The reason I ask is because I believe a new connection (and maybe even SSL negotiation) would have to be established for each image subdomain.

Thanks again for any advice - always a pleasure!

Sincerely,
Travis Walters

[quote=“freelancer-review.com, post:1, topic:9260”]
Greetings,

I was wondering what people’s thoughts are on doing this:

  • Inline ALL CSS on first page view (or until the user has it in their cache - can have an AJAX call to the server letting the server know this is complete)
  • On that same page view, have the last event that takes place (besides the AJAX call) download an external CSS stylesheet with the same CSS that was inlined so that it is cached for future calls
  • On future page views, serve the CSS as an async stylesheet in the HTML HEAD section (which should be cached at that point)

I was doing this just for CRITICAL CSS but I was having rendering above the fold issues that went away when I placed all css in the head inlined.

Initial thought on this procedure is that what if the user clears cache? Well, the cookie that stores the session variables (including the one that the ajax call would set) would be cleared. So what if the user clears cached images and files but not cookies? It would be rare but it could happen. However, since the CSS is async in the HTML HEAD, it would just download it again. Some people say it might defeat the purpose but it is rare that somebody would clear cache and then continue to use the website on that same visit. Future visits would have cookies expired.[/quote]

Sounds convoluted to me. Why not just inline critical CSS, and after DomContentLoaded, load a single, combined stylesheet from which critical CSS is drawn?

Just a note on this bit:

The rendering issues indicate that some CSS critical to the rendering were absent. Inlining different CSS on different pages is fine if that is what is called for to render each page optimally. It is doubly fine all pages are drawing from the same, one, combined CSS file.

We have found that (in most instances) so long as the HTML ends up under 50kB, there is no general performance impact (and when there is, it is easily mitigated). For a lot of sites, this of course means that all CSS can be inlined. Most people have a reflexive aversion to what I’ve just written there, but we’ve A/B tested and verified this hundreds of thousands of times across hundreds of properties. I encourage others to A/B test their own application(s) and see for themselves.

Best,
AJ
Managing Partner
WpFASTER

Hey There,

Thanks for the response!

I am not seeing an advanced view where I can quotes so I will do it the old fashion way.

“Sounds convoluted to me. Why not just inline critical CSS, and after DomContentLoaded, load a single, combined stylesheet from which critical CSS is drawn?”

That is what I am doing except instead of critical CSS, I am inlining all CSS. If there ever becomes a point where using this method effects performance, it would probably be best to just do critical css. The reason I am using all CSS at this point is because there is no performance impact and because it is a pain the butt to get that above the fold content warning to go away - even with automated programs available to do it for me. The automated programs seems to find about 65% of the content above the fold on my website and it seems like it is worse now that I load a bunch of stuff via AJAX.

“We have found that (in most instances) so long as the HTML ends up under 50kB, there is no general performance impact (and when there is, it is easily mitigated).”

That was the major thing I was wondering - the point at which CSS has to be reduced to be considered critical css. Glad to see you have done some testing to find this out. I am not sure it will be the same with everyone’s website, but it is a good reference point to start paying attention at the very least.

Sincerely,
Travis Walters

Hi,

I’m curious as to what performance degradation occurs above 50kb of HTML with inlined assets?

Mike

Hi Mike,

There are a lot of caveats to any answer that might be given to your question, so for the sake of clarity I’m going to omit some things and simplify others (hopefully not overly so).

On mobile, you actually run into RTT obstacles right around 14KB. But, we’ve found, that at around 20KB (50 KB for desktop) is when actual performance degrades for critical metrics such as first paint/start render and above-the-fold visual completion/time to interactivity.

Further on mobile, anything above 20KB really begins to grind down page-to-page navigation, the testing for which can’t be done with (as far as I know) any online tool. That said, this page-to-page navigation issue is pretty easy to mitigate with cache warming and PJAX.

Ideally, you really should inline critical assets and keep them as lean as possible for the quickest render across the widest range of scenarios and devices.

Best,
AJ
Managing Partner
WpFASTER | WordPress Optimization

Thanks for the clarification AJ.
Appreciated.

Mike