WordPress and Mod_Pagespeed – why combine_css does not work
20.10.2011 | 3 minutes of reading time
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:
1<link rel='stylesheet' id='login-css' href='wp-admin/css/login.css,qver=20110610.pagespeed.cf.ZqFxSZoD1J.css' type='text/css' media='all'/> 2<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:
1<link rel='stylesheet' id='login-css' href='wp-admin/css/login.css?ver=20110610' type='text/css' media='all'/> 2<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.
1function remove_style_id($link) {
2 return preg_replace("/id='.*-css'/", "", $link);
3}
4add_filter('style_loader_tag', 'remove_style_id');
This would result in the following HTML:
1<link rel='stylesheet' href='wp-admin/css/login.css?ver=20110610' type='text/css' media='all'/> 2<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:
1<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.
More articles
fromFabian Lange
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog author
Fabian Lange
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.