53

Google PageSpeed often suggests to optimize CSS delivery. It occurred to me that it would reduce network round trips to inline all the CSS like this:

<style type="text/css">

    @{ 
        var bootstrap = File.ReadAllText(Server.MapPath("bootstrap.min.css"));
        var bootstrapTheme = File.ReadAllText(Server.MapPath("theme.min.css"));
        var fontAwesome = File.ReadAllText(Server.MapPath("font-awesome.min.css"));
        var bigfont = File.ReadAllText(Server.MapPath("bigfont.min.css"));
        var bigfontPrint = File.ReadAllText(Server.MapPath("bigfont-print.min.css"));
    }

    @Html.Raw(bootstrap)
    @Html.Raw(bootstrapTheme)
    @Html.Raw(fontAwesome)
    @Html.Raw(bigfont)
    @Html.Raw(bigfontPrint)

</style>

This seems to be a reasonable solution to the problem of slow page loads and has increased my PageSpeed score to 95 from 88.

Putting code-style aside for the moment, what technical reasons, if any, exist for NOT in-lining all CSS in this way?

Salman A
  • 262,204
  • 82
  • 430
  • 521
Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467
  • Well my gut reaction was what happens when you want to update it? But i dont know anything about css and web programming so. Id see it like a long chain of if-elses: cumbersome and avoidable and a real pain to update. – D. Ben Knoble Sep 28 '15 at 02:03
  • @BenKnoble To update it, would it not be as easy as changing the CSS file and clicking save? – Shaun Luttin Sep 28 '15 at 02:04
  • 2
    Well see this is why i made the disclaimer. I assumed you were somehow talking about adding all the css as strings to a c# program since that was a tag and i am totally ignorant here. Oops? Im sure someone who understands what your talking about will have a better answer. – D. Ben Knoble Sep 28 '15 at 02:06
  • 3
    Interesting question. The same could be done for JS as well, no? @BenKnoble, he's saying the CSS is put inline programatically, so you'd still edit resource files the same way. – Orun Sep 28 '15 at 02:07
  • Ahhh gotcha. Thanks for that. – D. Ben Knoble Sep 28 '15 at 02:08
  • 2
    @OrunBhuiyan Yes. This is what I am thinking. It's done brilliantly for my page load. I am at 99/100 for mobile and desktop. – Shaun Luttin Sep 28 '15 at 02:08
  • 4
    So PageSpeed ignored that fact that you stuffed few hundred kilo bytes of CSS in your page. Weird. – Salman A Sep 28 '15 at 06:45
  • 6
    This seems like a bad idea. The CSS is never cached. In addition, shoving extra kB of data before your content is sure to make your page load slower. You could argue that `link` does this, however, `link` could be, at some point by some vendor, cause the linked files to be loaded asynchronously. You could never do that with CSS content shoved into your HTML page. There's a reason script tags are delegated until last - the same logic applies to all content – Dan Sep 28 '15 at 07:59
  • 1
    I am not familiar with ASP but does `ReadAllText()` cache files? I would imagine that reading from the disk 5 times for every single page load might cause some disk I/O performance issues for your server. This would also depend on the specs of your server and the expected pageviews/second. I am also going to imagine that assigning each file's contents into a variable is increasing RAM usage as well. – MonkeyZeus Sep 28 '15 at 16:36
  • 1
    You only need to inline "critical path CSS". Check out [critical](https://github.com/addyosmani/critical) for a way to automatically extract critical path CSS. – alexw Sep 28 '15 at 20:04
  • I agree with @alexw, here is an interesting article about critical css http://www.smashingmagazine.com/2015/08/understanding-critical-css/ – Tasos K. Sep 29 '15 at 18:27

4 Answers4

74

Inlining all your CSS means it cannot be cached, so every single page load will contain all of the CSS required, and when you are using large libraries that can really be a lot of wasted bandwidth. For example, Bootstrap is around 120k. Note the Google link you shared specifies the following (emphasis mine):

If the external CSS resources are small, you can insert those directly into the HTML document, which is called inlining.

So a single page load may be faster but overall it's likely to be slower.

Personally I would stay away from doing that. However, one thing you can do is bundle all of your CSS into a single request (you are using MVC so that is relatively simple) so you only have to do a single extra trip to the server for your CSS and all future pages requested by the browser will not need to ask for them again.

DavidG
  • 113,891
  • 12
  • 217
  • 223
  • Good answer. I am wondering about a combined solution. If the CSS is not cached, then inline/embed it and cache it; else, use the cached CSS. – Shaun Luttin Sep 28 '15 at 02:40
  • 2
    With that logic it will never cache the CSS to begin with. – Martheen Sep 28 '15 at 02:41
  • 4
    As with any sort of metric, it;s important to understand the drawbacks. For webpage speed testing, i tend to use http://www.webpagetest.org/ as the tests it runs tend to be more "real world". – DavidG Sep 28 '15 at 02:42
  • 2
    or use HTML/2... once good support for its "bundling" feature is implemented – 小太郎 Sep 28 '15 at 05:38
  • 9
    @ 小太郎, you mean HTTP 2 – ysdx Sep 28 '15 at 08:04
  • 4
    It's also worth remembering that generally things tend to get bigger as projects continue much more often than they get smaller. It's sadly much more common for what was once 5 lines of CSS to become 50 than for what was 50 lines to become 5. As such it can be worth either just assuming that much of the small code will become large (and so should be a separate resource) or else at least keep an eye on when they grow to consider if they should be moved. – Jon Hanna Sep 28 '15 at 11:19
  • @DavidG Yeah I didn't realize he meant internal not inline. Thanks. – MiniRagnarok Sep 28 '15 at 12:55
  • I can say for sure that, in a product used by the company I'm working with, we have reduced the loading time from 3-4 seconds to 1-2 seconds for over 50KB of CSS goodness. Combining CSS files is a great idea, specially if you keep them in a cached directory. – Ismael Miguel Sep 28 '15 at 17:39
  • What would you do about a small piece of css that's only useful on a single page? Inline that or add it to your master css file? – corsiKa Sep 29 '15 at 15:09
  • @corsiKa Good question. Honestly I'd probably add it to the master CSS (or bundle it in at least) if only to avoid getting into page specific CSS files. – DavidG Sep 29 '15 at 15:12
  • [here](http://www.dotnet-tricks.com/Tutorial/mvc/c72b040113-Asp.net-MVC-4-performance-optimization-with-bundling-and-minification.html) is a live example on **MVC performance optimization with bundling and minification** Hope helps someone. – Shaiju T Oct 04 '15 at 13:35
16

No one has mentioned the intended use case for this technique, which is definitely not to load 100% of your css. Rather, this technique is meant to make users think the page has loaded faster.

When we discuss making pages load faster, the real goal is generally to make the page load seem faster. From the perspective of the user experience, this is much more important than actually making the load take less time. It doesn't matter if the whole page take 500ms to load, because a human can't parse it that quickly anyway. What matters is how quickly the page appears to have loaded.

So the appropriate usage of this technique is to load, immediately, the absolutely essential css to make the page render properly. That is, there are some css rules that make the images be the right size, that make things float correctly, that avoid that horrible appearance of page content jumping around the page while the facebook SDK finishes its business. That code needs to be present in the same instant the markup is loaded. Solution: inline that critical css.

But definitely DO NOT inline all of the css. There can be another 100kb that loads later, if that css only styles content that is loading asynchronously anyway. But if there is page structure that must be in the correct form after 25ms, that css should be inlined.

Seth Battin
  • 2,811
  • 22
  • 36
10

You misunderstood the PageSpeed suggestion. The recommendation is for small CSS files:

If the external CSS resources are small, you can insert those directly into the HTML document, which is called inlining. [...] Keep in mind if the CSS file is large, completely inlining the CSS may cause PageSpeed Insights to warn that the above-the-fold portion of your page is too large via Prioritize Visible Content.

In fact, the article later suggests a balanced approach for large CSS files: inline critical CSS and defer-load the remaining CSS file.


Now, even if PageSpeed gives you a decent score after inlining large CSS files* it might still be a bad idea:

Redundancy

Inline CSS files means you duplicate the <style>...</style> tag across pages. This means you serve redundant data for subsequent or repeat page views. The redundant data costs bandwidth and increases download time.

Separate CSS file along with strong caching headers allow you to eliminate redundancy. Caching headers instruct the browsers to cache the CSS file on first page view and reuse on subsequent or repeat page views.

Content vs Data

Inline CSS files reduce the proportion of "actual" content on the page. Inline CSS files require you to insert the CSS above the content while most of us strive to put the actual content near the top HTML.

Inline CSS will also cause the browser to download additional bytes before allowing it to download other resources such as JavaScript and images.

Compression Cost

If your HTML page is generated dynamically then, most likely, it will be served uncompressed. Some servers (e.g. IIS) and software (e.g. Wordpress) allow compression of dynamic content but requires more CPU + Memory compared to compression of static content (e.g. CSS files). This is yet another reason why you should keep CSS in separate file.

For the above reasons I would keep my CSS combined, minified, compressed and cached, in a separate file, even for one page websites.


* Not to be confused with inline styles

Community
  • 1
  • 1
Salman A
  • 262,204
  • 82
  • 430
  • 521
5

This is too long to fit in a comment. There where I work, we use Content Security Policy header directives (specifically style-src) to explicitly prohibit the use of inline CSS. The rationale not to use inline CSS in this case is minimizing the risks of CSS injection for pages created dynamically. OWASP has detailed information about this topic, including exploit samples: https://www.owasp.org/index.php/Testing_for_CSS_Injection_(OTG-CLIENT-005). If only static content is served to the browser, there should be no risk.

GOTO 0
  • 42,323
  • 22
  • 125
  • 158