RenderBlocking

Pagespeed For WordPress 3: Render-Blocking Resources

If you’ve been following along with this series of posts, chances are you’ve tried running a page speed test or two on your own website. If that’s the case, you’ll no doubt have come across that annoying and somewhat cryptic phrase "Eliminate render-blocking resources" in your audit results.

So, what exactly does that mean? Well, in this context, a render-blocking resource is probably best defined as a ‘non-critical resource that a page attempts to load before the primary content, thus delaying the primary content from rendering on the user’s screen’. OK, that’s a mouthful.

For instance, let’s say a user visits your WordPress site with the intent of viewing your latest post. They click the link and the page starts loading… But, the page they’re trying to access is configured in such a way that prevents the main content of the page from showing up on their screen in a timely manner.

As a result, the user is forced to wait for the non-critical JavaScript and/or CSS to load before they can get at what they’re really after: the primary content of your post.

In order to remedy this, we need to set things up so that the important stuff loads first, and the less-important stuff gets loaded later — after the primary content becomes visible on screen.

This is actually much easier to pull off if you’re manually coding a page from scratch. In the WordPress environment, however, things can get a little more complex – especially if you take into account the fact that just about every plugin you install/activate will introduce additional non-critical CSS and JavaScript into the mix.

Note that it is highly recommended that you do NOT modify your core WordPress or theme files – it’s advisable to create a child theme and make any edits/changes to those files instead. Don’t say we didn’t warn you.

We should also point out that the following optimization methods will only work on external javascript & CSS (i.e. if the script or CSS is not hard-coded into your HTML).

Deferring non-critical JS

The first order of business is to try and identify which resources are critical to the initial display of the page — after identifying the critical stuff, we can then configure it so that it will defer (postpone) downloading of any non-critical resources.

SO… If we were manually coding a web page and we wanted to make use of an external javaScript file, we’d include something like this inside the <head> section of our HTML:

<script type="text/javascript" src="scripts/myJavaSript.js"></script>

In the above example, the script would be loaded and executed immediately, before the browser has had a chance to parse the page. If we wanted to postpone this until after the primary elements of the page have been loaded, we’d simply add a ‘defer’ attribute somewhere within the <script> tag:

<script defer type="text/javascript" src="scripts/myJavaSript.js"></script>

In WordPress, however, since the <head> of our page is dynamically generated, we don’t necessarily have direct control over the code that goes into it — manually coding this is not really an option.

On the other hand, we do have the option of editing our child theme’s functions.php file which will allow us to manipulate our <script> tags programmatically:

function js_defer_attr($tag){

    // Do not defer these scripts.
    $scripts_to_exclude = array('jquery.js');

    foreach($scripts_to_exclude as $exclude_script){
        if(true == strpos($tag, $exclude_script ) )
            return $tag;
        }
    
        // defer all remaining scripts
            return str_replace( 'type', 'defer type', $tag );
}

add_filter( 'script_loader_tag', 'js_defer_attr', 10 );

Let’s walk through the above function example and see what it actually does:

  1. First, if there are any scripts that we do not want to defer (in this case, ‘jquery.js’) we add them to our $scripts_to_exclude array.
  2. Next, the function goes through the scripts listed in our $scripts_to_exclude array and returns the tag without any modifications.
  3. Finally, the ‘defer’ attribute is added to the remaining <script> tags.

Keep in mind that that in some instances, there may be external javaScript files that are shared by both the front-end and back-end of your site, and deferring certain scripts may cause your WordPress admin to behave and/or display erratically. You can get around this by wrapping the add_filter action in a conditional statement:

if (!(is_admin() )) {
    add_filter( 'script_loader_tag', 'js_defer_attr', 10 );
}

… which will apply the filter only to your front-end pages.

Dealing with Render-Blocking CSS

Another important area that should be looked at here would be render-blocking external CSS files. As with external javaScript, this is an issue that can be compounded whenever a new plugin is installed, and still more CSS is added to the mix.

Dealing with render-blocking CSS is not quite as straightforward as it is with render-blocking javaScript — once you get your head wrapped around the process, however, it actually becomes quite easy.

First, you need to identify critical ‘above-the-fold’ CSS (i.e. the style rules that are essential for the initial display of the page).

There are a number of online tools that will make easy work of this for you — the Critical Path Generator at pegasaas.com for example. All you need to do is enter a URL and the generator will extract the CSS required for your above-the-fold content.

Once you’ve done this, you’ll have a minified version of your critical CSS, which you can then copy & paste into your header.php file before the closing </head> tag. Or, if you prefer, you could add the following to your child theme’s functions.php file:

function critical_css() {
    ?>
    <style>
           [your critical css goes here]
    </style>
    <?php
}

Whichever method you decide to use, remember that you’ll need to wrap the minified CSS in the appropriate <style>…</style> tags.

Next, we want to postpone the loading of the remaining (non-critical) CSS by using the preload attribute. In order to accomplish this, we’ll add the following function to our functions.php file:

function add_rel_preload($html, $handle, $href, $media) {
    
    if (is_admin())
        return $html;

     $html = <<<EOT
<link rel='preload' as='style' onload="this.onload=null;this.rel='stylesheet'" id='$handle' href='$href' type='text/css' media='all' />
EOT;
    return $html;
}
add_filter( 'style_loader_tag', 'add_rel_preload', 10, 4 );

Similar to the ‘defer’ function we looked at earlier, the above function will add a rel=’preload’ attribute for each of the external CSS files referenced in the <head> portion of our document.

Leave a Reply

Your email address will not be published. Required fields are marked *