Should I inline all CSS files programmatically to optimize page load speed?

C#HtmlCssasp.net MvcPagespeed

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

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.

Solution 3 - C#

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

Solution 4 - C#

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShaun LuttinView Question on Stackoverflow
Solution 1 - C#DavidGView Answer on Stackoverflow
Solution 2 - C#Seth BattinView Answer on Stackoverflow
Solution 3 - C#Salman AView Answer on Stackoverflow
Solution 4 - C#GOTO 0View Answer on Stackoverflow