Search code examples
javascriptpagespeed

Run code after deferred CSS is loaded


The following snippet is provided in Google PageSpeed Tools - Insights - Optimize CSS Delivery which suggests that this should be used to defer loading of less important external stylesheets until after the initial render.

How can I run a piece of code after those CSS files have successfully loaded?

 <html>
  <head>
    <style>
      .blue{color:blue;}
    </style>
    </head>
  <body>
    <div class="blue">
      Hello, world!
    </div>
    <noscript id="deferred-styles">
      <link rel="stylesheet" type="text/css" href="small.css"/>
    </noscript>
    <script>
      var loadDeferredStyles = function() {
        var addStylesNode = document.getElementById("deferred-styles");
        var replacement = document.createElement("div");
        replacement.innerHTML = addStylesNode.textContent;
        document.body.appendChild(replacement)
        addStylesNode.parentElement.removeChild(addStylesNode);
      };
      var raf = requestAnimationFrame || mozRequestAnimationFrame ||
          webkitRequestAnimationFrame || msRequestAnimationFrame;
      if (raf) raf(function() { window.setTimeout(loadDeferredStyles, 0); });
      else window.addEventListener('load', loadDeferredStyles);
    </script>
  </body>
</html>

Solution

  • I would like to run a piece of code after those .css files have successfully loaded. Is there any way to ensure that?

    One of the simpler options to run your code after all of this is completed, is to wrap first function's invokation in a function statement, then insert your code after that invokation.

    var loadDeferredWrapper = function() {
        loadDeferredStyles();
        // Do Something
    }
    
    var raf = requestAnimationFrame || mozRequestAnimationFrame ||
        webkitRequestAnimationFrame || msRequestAnimationFrame;
    if (raf) raf(function() { window.setTimeout(loadDeferredWrapper, 0); });
    else window.addEventListener('load', loadDeferredWrapper);

    Another option would be to insert your function call directly into the end of the first function, this is essentially the same thing, but doesn't have as clear of a separation between scripts.

    var loadDeferredStyles = function() {
        var addStylesNode = document.getElementById("deferred-styles");
        var replacement = document.createElement("div");
        replacement.innerHTML = addStylesNode.textContent;
        document.body.appendChild(replacement)
        addStylesNode.parentElement.removeChild(addStylesNode);
        // Do Something
    };