CSS delivery optimization: How to defer css loading?

JavascriptHtmlCssGoogle PagespeedDeferred Loading

Javascript Problem Overview


I am trying to optimize the CSS delivery following the google documentation for developers https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery#example

As you can see in the example of inlining a small CSS file the critical CSS in inlined in the head and the original small.css is loaded after onload of the page.

<html>
  <head>
    <style>
      .blue{color:blue;}
    </style>
    </head>
  <body>
    <div class="blue">
      Hello, world!
    </div>
  </body>
</html>
<noscript><link rel="stylesheet" href="small.css"></noscript>

My question regarding this example:

How to load a large css file after onload of the page?

Javascript Solutions


Solution 1 - Javascript

If you don't mind using jQuery, here is a simple code snippet to help you out. (Otherwise comment and I'll write a pure-js example

function loadStyleSheet(src) {
    if (document.createStyleSheet){
        document.createStyleSheet(src);
    }
    else {
        $("head").append($("<link rel='stylesheet' href='"+src+" />"));
    }
};

Just call this in your $(document).ready() or window.onload function and you're good to go.

For #2, why don't you try it out? Disable Javascript in your browser and see!

By the way, it's amazing how far a simple google search can get you; for the query "post load css", this was the fourth hit... http://www.vidalquevedo.com/how-to-load-css-stylesheets-dynamically-with-jquery

Solution 2 - Javascript

A little modification to the function provided by Fred to make it more efficient and free of jQuery. I am using this function in production for my websites

		// to defer the loading of stylesheets
		// just add it right before the </body> tag
		// and before any javaScript file inclusion (for performance)  
		function loadStyleSheet(src){
			if (document.createStyleSheet) document.createStyleSheet(src);
			else {
				var stylesheet = document.createElement('link');
				stylesheet.href = src;
				stylesheet.rel = 'stylesheet';
				stylesheet.type = 'text/css';
				document.getElementsByTagName('head')[0].appendChild(stylesheet);
			}
		}

Solution 3 - Javascript

This is how you do it using the new way:

<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
  • link rel="preload" as="style" requests the stylesheet asynchronously.
  • The onload attribute in the link allows the CSS to be processed when it finishes loading.
  • "nulling" the onload handler once it is used helps some browsers avoid re-calling the handler upon switching the rel attribute.
  • The reference to the stylesheet inside of a noscript element works as a fallback for browsers that don't execute JavaScript.

Solution 4 - Javascript

In addition to Fred's answer:

Solution using jQuery & Noscript

<html>
  <head>
    <style>
      .blue{color:blue;}
    </style>
    <script type="text/javascript" src="../jquery-1.4.2.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function(){
        if($("body").size()>0){
                if (document.createStyleSheet){
                    document.createStyleSheet('style.css');
                }
                else {
                    $("head").append($("<link rel='stylesheet' 
                    href='style.css' 
                    type='text/css' media='screen' />"));
                }
            }
        });
    </script>
    </head>
  <body>
    <div class="blue">
      Hello, world!
    </div>
  </body>
</html>
<noscript><link rel="stylesheet" href="small.css"></noscript>

from http://www.vidalquevedo.com/how-to-load-css-stylesheets-dynamically-with-jquery

Using pure Javascript & Noscript

<html>
  <head>
    <style>
      .blue{color:blue;}
    </style>
    <script type="text/javascript">
          var stylesheet = document.createElement('link');
          stylesheet.href = 'style.css';
          stylesheet.rel = 'stylesheet';
          stylesheet.type = 'text/css';
          document.getElementsByTagName('head')[0].appendChild(stylesheet);
    </script>
    </head>
  <body>
    <div class="blue">
      Hello, world!
    </div>
  </body>
</html>
<noscript><link rel="stylesheet" href="small.css"></noscript>

Solution 5 - Javascript

Try this snippet

The author claims it was published by Google's PageSpeed Team

<script>
    var cb = function() {
    var l = document.createElement('link'); l.rel = 'stylesheet';
    l.href = 'yourCSSfile.css';
    var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h); };
    var raf = requestAnimationFrame || mozRequestAnimationFrame ||
              webkitRequestAnimationFrame || msRequestAnimationFrame;
    if (raf) raf(cb);
    else window.addEventListener('load', cb);
</script>

Solution 6 - Javascript

WARNING: body{background-image: url("http://example.com/image.jpg");} in css files will make your css files still render-blocking.

If you tried all the solutions above and you still get the render-blocking warning from PageSpeed insights then you probably have this style rule in your css files. After hours of tests it turns out that this rule is what making ALL of my css to be flagged as render-blocking resources at PageSpeed insights. I found the same issue has been discussed before.

I don't know why body{background-image: url(...) do this for all the css files!, although I have different images resources in the file for the buttons, icons, ...etc .

I fixed this by moving this rule from the .css file and put it in the inline styles. Unfortunately, you will have to break your css plan and put the rule in all of your layouts HTML files instead of being in 1 css file that is imported in all of your HTML layouts, but the 90s and green color in PageSpeed insights deserve it.

Solution 7 - Javascript

There is a simple way to load CSS asynchronously with only link tag

<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">
  1. media="print" tell browser to load CSS asynchronously that intended for print.
  2. Onload set the link's media to all when it loaded.
  3. Comapared to mahmoud answer, this approach doesn't prioritize fetching the css, which maybe not needed

More details are explained here

Solution 8 - Javascript

Fixed mine by introducing placing all css files at the bottom of the page, after the body tag. but this introduces a new problem, the page loads un-styled html for noticeable mili seconds before applying the style. For this I fixed by introducing a splash screen all styled on the page.

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
QuestionRafaSashiView Question on Stackoverflow
Solution 1 - JavascriptFredView Answer on Stackoverflow
Solution 2 - JavascriptSalvi PascualView Answer on Stackoverflow
Solution 3 - JavascriptMahmoudView Answer on Stackoverflow
Solution 4 - JavascriptRafaSashiView Answer on Stackoverflow
Solution 5 - JavascriptRaja KhouryView Answer on Stackoverflow
Solution 6 - JavascriptAccountant مView Answer on Stackoverflow
Solution 7 - JavascriptzulvkrView Answer on Stackoverflow
Solution 8 - JavascriptMrJaidView Answer on Stackoverflow