WordPress and Mod_Pagespeed – why combine_css does not work

In a recent talk about Web Performance Optimization during the Web Tech Conference I recommended mod_pagespeed as a cool automatic tool to reduce requests to CSS and JavaScripts and, by that, improve website load performance. But I noticed while watching stats for www.codecentric.de that mod_pagespeed does not work correctly.

It should combine a few CSS files, but I found them separate in HTML:

<link rel='stylesheet' id='login-css' href='wp-admin/css/login.css,qver=20110610.pagespeed.cf.ZqFxSZoD1J.css' type='text/css' media='all'/>
<link rel='stylesheet' id='colors-fresh-css' href='wp-admin/css/colors-fresh.css,qver=20110703.pagespeed.cf.ldpZyBlEpG.css' type='text/css' media='all'/>

Ok, this is at least a minified version of the CSS files. Without pagespeed it would have looked like this:

<link rel='stylesheet' id='login-css' href='wp-admin/css/login.css?ver=20110610' type='text/css' media='all'/>
<link rel='stylesheet' id='colors-fresh-css' href='wp-admin/css/colors-fresh.css?ver=20110703' type='text/css' media='all'/>

Those two lines should have been combined by the “combine_css” filter. But indeed the documentation has a few notes on when this does not happen:

The CSS Combine filter operates within the scope of a “flush window”. Specifically, large, or dynamically generated HTML files may be “flushed” by the resource generator before they are complete. When the CSS combiner encounters a flush, it will emit all CSS combinations seen up to the point of the flush. After the flush, it will begin collecting a new CSS combination.

and

IE Directives containing CSS links form a “barrier” for the CSS combiner. Multiple CSS elements found before an IE directive are combined together immediately before the IE directive. Multiple CSS elements found after are also combined, but the combination does not span across the IE directive, as that would affect the order that the browser sees the CSS elements.

However, here we do not have IE directives, nor are both lines in different “flush-window”s. So why doesn’t it work?

There is another, not documented, constraint:

Tags can only be combined when no information will get lost.

In this simple example it is easy to see what this lost information would be: The identifier of the link tags, “login-css” and “colors-fresh-css”, would no longer exist. It would be theoretically possible to use these identifiers from JavaScript code to retrieve and modify the css.

But where does the ID come from? Do we actually need them, or can we get rid of them?

WordPress uses a function called “wp_enqueue_style” which can be used by plugins or themes to add styles dynamically to the head-section. wp_enqueue_style takes a mandatory first parameter called hande. And this handle is what WordPress will use to generate the ID.
Usually you do not need the ID. There is actually no code in standard WordPress which would use it, and one would rarely ever write code using is on stylesheet links yourself. WordPress is just adding the id for any case.
To make it possible for mod_pagespeed to combine the CSS files, we need to remove the ID. This is easily possible using a built-in WordPress filter. The “style_loader_tag” filter is called on the final link, and we can hook into it to remove the id.

function remove_style_id($link) {
        return preg_replace("/id='.*-css'/", "", $link);
}
add_filter('style_loader_tag', 'remove_style_id');

This would result in the following HTML:

<link rel='stylesheet' href='wp-admin/css/login.css?ver=20110610' type='text/css' media='all'/>
<link rel='stylesheet' href='wp-admin/css/colors-fresh.css?ver=20110703' type='text/css' media='all'/>

And indeed the tags are combined as expected:

<link rel="stylesheet" type="text/css" href="wp-admin/css/login.css,,qver==20110610+colors-fresh.css,,qver==20110703,Mcc.35EZfaJvqU.css.pagespeed.cf.I5odih6TFY.css" media="all"/>

I should also mention that this behaviour is not restricted to the ID. It is valid for other attributes as well, especially “media”. If you serve different styles for different medias, they of course cannot be combined. I would recommend to check that you use the medias correctly, or, if you do not need the distinction between medias, to remove the media attribute as well.

  • Facebook
  • Delicious
  • Digg
  • StumbleUpon
  • Reddit
  • Blogger
  • LinkedIn
Fabian Lange

7 Responses to WordPress and Mod_Pagespeed – why combine_css does not work

  1. Javi Arques says:

    It works perfectly, thank you very much!!!

  2. Oh my god, yes! This is exactly why they aren’t combining. It’s only been 3 days since I installed mod_pagespeed and it’s been driving me crazy that css and javascript files aren’t combining. I think it’s probably a similar issue with the javascript too.

    Thanks for this. It’s gonna take all of a minute to impliment and I just wasted 3 days with mediocre tweak that done nothing haha

  3. Totally brilliant!

    I was having a think that the ID might be the case … but I wasn’t quite yet ready to delve into the WordPress code to try and figure out which filter I might need to amend.

    This is the solution – thank you for publishing this.

  4. what about JavaScript ?

  5. Thanks Fabian, I had the same problem with Mage_speed

    I’m gonna ask the same as other readers, any idae about the JavaScript files?

    Cheers.

  6. Fabian, excellent article.

    Since this snippet of code might be interesting for more and more people, I decided to create a “oneliner” plugin from it.

    It is available on https://github.com/primozcigler/remove-css-ids and is waiting for the review on wordpress.org.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>