WordPress und Mod_Pagespeed – Warum combine_css nicht funktioniert

1 Kommentar

In meinem Vortrag über Web Performance Optimization auf der Web Tech Conference erwähnte ich mod_pagespeed als super funktionierende automatische Lösung um Requests von CSS und JavaScripts zu reduzieren und so Webseiten schneller zu machen. Doch dann fiel mir beim Betrachten der Statistiken von www.codecentric.de auf, dass mod_pagespeed gar nicht korrekt funktionierte.

Eigentlich sollten mehrere CSS Dateien zu einer zusammengefügt werden, doch ich fand diese Anweisungen im 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, das ist zumindest schonmal die von Pagespeed verarbeitete, d.h. minifizierte, Version der CSS Dateien. Ohne Pagespeed sähe die Stelle so aus:

<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'/>

Diese zwei Zeilen sollte eigentlich von dem Filter „combine_css“ zu einer Zeile zusammengefasst werden. Die Dokumentation beschreibt aber, dass dies in der Tat nicht immer passiert:

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.

und

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.

Jedoch ist hier weder eine IE Direktive, noch sind die beiden Zeilen nicht im gleichen „Flush-Fenster“. Warum funktioniert es also nicht?

Es gibt tatsächlich eine, leider nicht dokumentierte, weitere Bedingung:

Tags können nur zusammengefasst werden wenn dadurch keine Information verloren geht.

Welche Information dies in diesem Beispiel wäre, kann man relativ leicht feststellten: Die beiden Identifier „login-css“ und „colors-fresh-css“ könnten dann nicht weiterexistieren. Es wäre ja denkbar, dass diese Identifier von JavaScript Code verwendet würden, um das CSS zu modifizieren oder andere Dinge zu tun.

Aber wo kommen diese IDs eigentlich her? Brauchen wir sie? Und wie können wir sie loswerden?

WordPress besitzt eine Funktion namens „wp_enqueue_style“ mit der Plugin- und Themeentwickler Styles dynamisch in den head-Bereich einfügen können. wp_enqueue_style nimmt als ersten Parameter ein sogenanntes handle. Genau dieses handle verwendet WordPress um sie als ID zu verwenden.
In der Regel braucht man die ID nicht, da es keinen standardmäßig vorhandenen Code gibt, der über die ID der Styles an die Style-links geht. Und selber wird man wahrscheinlich auch keinen Code schreiben, der IDs auf Style link Tags benötigt. WordPress fügt die ID der vollständigkeit halber an.
Damit mod_pagespeed die CSS Dateien zusammenfügen kann, muss sie jedoch weg. Das ganze geht am einfachsten über WordPress Filter. Es gibt nämlich einen Filter der für den fertigen Style Link Tag aufgerufen wird: „style_loader_tag“.

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

Dies würde dann in folgendem HTML resultieren:

<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'/>

Und es wird nun in der Tat korrekt zusammengefasst:

<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"/>

Abschließend bleibt noch zu erwähnen, dass die gleiche Einschränkung auch für „media“ gilt. Bietet man Styles für verschiedene Medien an, können diese ebenfalls nicht zusammengefasst werden. Hier sollte man entsprechend prüfen ob man die Unterscheidung braucht, alle CSS den richtigen media-Typ haben und gegebenenfalls das media Attribut entfernen.

Autor

Fabian Lange

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentare

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *