Warum 100 PageSpeed-Punkte oft nicht erstrebenswert sind

Google stellt mit PageSpeed Insights einen schönen „Geschwindigkeits“-Test für Websites zur Verfügung. Doch es ist oft gar nicht so erstrebenswert, 100 / 100 Punkte zu bekommen, denn: das würde dem eigentlichen Ziel zuwider laufen. Warum?

PageSpeed testet gar nicht die Geschwindigkeit einer Seite

Zunächst muss man sich klar machen, dass Google PageSpeed Insights gar kein Geschwindigkeitstest ist. Es ist vielmehr ein Test, bei der die meisten Parameter etwas mit der Seitengeschwindigkeit zu tun haben. Hat man einen guten PageSpeed-Wert, kann man trotzdem noch eine für Benutzer unfassbar langsame Website haben.

Der PageSpeed von binary-butterfly.de: Ohne volle Punktzahl perfekt.
Der PageSpeed von binary-butterfly.de: Ohne volle Punktzahl perfekt.

Der einzige echte Geschwindigkeitstest ist unter dem Punkt „Antwortzeit des Servers reduzieren“ zu finden. Hat man dort eine zu hohe Zeit, ist das ein direkter Hinweis auf eine zu langsame Reaktion des Servers. Andere Probleme wie langsame AJAX Requests, wie live generierte (und damit langsame) CSS- oder JS-Dateien sind auf PageSpeed nicht sichtbar. Um diese zu finden, kann man das Network-Tab von Firebug oder auch Online-Tools wie den Pingdom Website Speed Test nutzen.

Wie man hohe PageSpeed-Werte erreicht

Google PageSpeed ist am Ende eine Anzeige, wie sauber das Theme und Plugins programmiert wurden. Diese Seite hier ist ein schönes Beispiel dafür: Ich habe genau nichts extra dafür gemacht, nur um den PageSpeed zu erhöhen. Überhaupt habe ich nur zwei Kleinigkeiten gemacht, die den PageSpeed erhöhen. Einerseits sorge ich mit dem folgenden Snippet dafür, dass jQuery im Footer geladen wird (was WordPress von alleine nicht macht):

add_action( 'wp_enqueue_scripts', function() {
  global $wp_version;
  wp_deregister_script( 'jquery' );
  wp_deregister_script( 'jquery-migrate' );
  wp_register_script( 'jquery', includes_url( '/js/jquery/jquery.js' ), false, (string)$wp_version, true );
  wp_register_script( 'jquery-migrate', includes_url( '/js/jquery/jquery-migrate.min.js' ), array('jquery'), (string)$wp_version, true );
  wp_enqueue_script( 'jquery' );
  wp_enqueue_script( 'jquery-migrate' );
});

Und andererseits sorge ich dafür, dass Contact Form 7 seine CSS-Datein nicht lädt, weil ich die eh mit Bootstrap-eigenen CSS-Regeln überschreibe:

add_filter( 'wpcf7_load_css', '__return_false' );

Der Rest ist die Standard-Konfiguration meines Webservers

  • eine Reihe an Nginx-Regeln (vergleichbar mit .htaccess Regeln) kümmert sich um die korrekte Auslieferung der Dateien (z.B. gzip)
  • Nginx FCGI Caching liefert ein extrem schnelles Seitenausgabe-Caching
  • CSS- und JS-Dateien wurden bereits bei der Theme-Entwicklung zusammengefasst und minifiziert
  • Die Bildergrößen sind eh schon richtig, weil ich als Entwickler des Themes auch von vorne herein wusste, welche Größen ich brauche.

Im Ergebnis gibt es bei mir mobil 85 / 100 Punkte und auf dem Desktop 95 / 100 Punkte, ganz ohne jede Optimierung.

Übrigens: natürlich ist es deutlich schwerer, mit Multi-Purpose-Themes und einer riesigen Menge Plugins derartige Werte einfach so zu erreichen. Aber genau das ist ja auch der Punkt: aus technischer Sicht sind viele dieser Themes und Plugins einfach schlecht programmiert, und manche Fehler liegen auch in der Natur der Sache: wenn Du jede Bildgröße in einer ultraflexiblen Zusammenstellung erlauben willst, dann kannst Du vorher nun mal nicht die korrekte Bildgröße kennen, und dann musst Du zwangsweise zu große Bilder verwenden.

Kurzum: mit sauberem Code bekommt man ganz automatisch recht gute Werte. Aber wieso eigentlich nicht 100 / 100 Punkten?

Rendering blockende Dateien

Um zu verstehen, warum wir keine 100 Punkte erreichen wollen, müssen wir uns mit dem konkreten technischen Grund für die Herabstufung beschäftigen. Dieser lautet:

JavaScript- und CSS-Ressourcen, die das Rendering blockieren, in Inhalten „above the fold“ (ohne Scrollen sichtbar) beseitigen

Es ist übrigens immer hilfreich, die konkret von PageSpeed aufgelisteten Probleme zu betrachten, da die Punktezahl selbst einem nicht bei der Behebung der Probleme helfen kann. In diesem Fall sind es rendering-blockierende Dateien. Aber was ist das eigentlich? Dafür müssen wir uns einmal kurz die Struktur der Seite anschauen:

<!DOCTYPE html>
<html>
  <head>
    <title>Mein toller Titel</title>
    [...]
    <link rel='stylesheet' href='https://binary-butterfly.de/mein/tolles/stylesheet.css' type='text/css' media='all' />
  </head>
  <body>
    <div>
      Meine Inhalte
    </div>
    <script type='text/javascript' src='https://binary-butterfly.de/mein/tolles/javascript.js'>
  </body>
</html>

Der Browser liest das HTML von oben nach unten. Bereits während er die Datei liest, beginnt der Browser zu rendern, lies: die einzelnen HTML-Teile zu der nachher sichtbaren Seite zusammenzusetzen. Stößt er auf eine eingebundene Datei wie im obrigen Beispiel das stylesheet.css, muss er diese erst vollständig laden, um weitermachen zu können. Das stylesheet blockt also das Rendern – daher der Name.

Das Script javascript.js wird dagegen erst nach dem Inhalt geladen. Der Browser kann also den gesamten Inhalt rendern und so dem Nutzer schnell anzeigen, bevor der Browser das JavaScript laden muss. Das javascript.js ist daher nicht Rendering-blockierend.

flash of unstyled content

Eine der Lösungen für Rendering-blockierende Ressourcen ist, die Ressourcen einfach nach unten zu schieben. Das wurde in dem Beispiel mit dem JavaScript gemacht – und mit Scripten funktioniert das (sauberer Code vorausgesetzt) auch sehr gut, da diese eh eine fertig geladene Website-Struktur brauchen, um zu funktionieren.

Bei CSS-Dateien ist das dagegen keine besonders gute Idee. Modifizieren wir unser Beispiel ein wenig:

<!DOCTYPE html>
<html>
  <head>
    <title>Mein toller Titel</title>
    [...]    
  </head>
  <body>
    <div>
      Meine Inhalte
    </div>
    <link rel='stylesheet' href='https://binary-butterfly.de/mein/tolles/stylesheet.css' type='text/css' media='all' />
    <script type='text/javascript' src='https://binary-butterfly.de/mein/tolles/javascript.js'>
  </body>
</html>

Jetzt kann der Browser sämtliche Inhalte anzeigen, ohne auf irgendwelche Ressourcen zu warten. Stattdessen sieht man aber ganz kurz die Inhalte der Website ohne jedes Design aufblitzen. Warum?

In der CSS-Datei (Style-Sheet) befinden sich die Regeln für das Aussehen der Website. Der Browser geht wie immer von oben nach unten und rendert live mit. Das bedeutet, dass der Browser erst mal die Inhalte komplett ohne Design darstellt, von den Design-Regeln erfährt er ja erst ganz am Ende. Da die Inhalte ohne Design-Regeln recht hässlich sind, fällt das auch hässlich auf. Daher auch der Name: es flashed kurz der unstyled Content auf, bis eben die CSS-Datei geladen wird. Wenn man ein wenig Wert auf Ästhetik legt, ist das also keine Option (außerdem ist es widersinnig, da es ja darum geht, die Seite möglichst schnell benutzbar zu machen – und eine ungestylte Seite ist nun sicherlich nicht nutzbar.

Sämtliche CSS-Regeln inline

Viele Caching-Plugins sind mittlerweile dazu übergegangen, einfach sämtliche CSS-Regeln inline im <head>-Bereich einzubinden, statt sie aus einer externen Datei zu laden. Das sieht dann in etwa so aus:

<!DOCTYPE html>
<html>
  <head>
    <title>Mein toller Titel</title>
    <style>
      [...] Meine kompletten CSS-Regeln [...]
    </style>
    [...]    
  </head>
  <body>
    <div>
      Meine Inhalte
    </div>
    <script type='text/javascript' src='https://binary-butterfly.de/mein/tolles/javascript.js'>
  </body>
</html>

Der PageSpeed-Test ist damit glücklich: der Browser muss nicht mehr auf eine Datei warten. Auch der Nutzer ist zunächst glücklich: er bekommt alle Inhalte ohne flash of unstyled content angezeigt. Also alles super?

Nein. Das zentrale Problem liegt an der Menge der CSS-Regeln, und genau dadurch macht man am Ende seine Seite eher langsamer als schneller. Denn: so eine CSS-Datei ist ganz schön groß – hier mal als Beispiel die noch recht kleine CSS-Datei dieser Seite hier. All diese CSS-Regeln müssen nun in den HTML-Kopfbereich. Dadurch kommt sehr sehr viel CSS auf sehr, sehr wenige Inhalte – das Verhältnis zwischen Inhalten und helfenden Elementen wie HTML-Tags oder eben CSS ist nicht mehr gewahrt. Das kreidet manch ein SEO-Tool zu Recht an.

Wenn ein Besucher nun weiter auf der Seite bleibt, ist dieses Verfahren sogar zum Geschwindigkeits-Nachteil: da die CSS-Regeln im Header sind, müssen die CSS-Regeln bei jeder einzelnen aufgerufenen Seite mit ausgeliefert werden. Damit muss man am Ende viel mehr Daten übertragen, als es eigentlich notwendig ist. Die externe CSS-Datei würde nämlich nur ein einziges mal geladen werden, bei allen weiteren Seitenabrufen wäre sie im Browser-Cache und daher sofort verfügbar.

Der Königsweg: CSS aufsplitten

Die Empfehlung von Google lautet daher, die CSS-Regeln aufzusplitten. Das sähe dann so aus:

<!DOCTYPE html>
<html>
  <head>
    <title>Mein toller Titel</title>
    <style>
      [...]Meine wichtigen CSS-Regeln[...]
    </style>
    [...]    
  </head>
  <body>
    <div>
      Meine Inhalte
    </div>
    <link rel='stylesheet' href='https://binary-butterfly.de/mein/tolles/stylesheet.css' type='text/css' media='all' />
    <script type='text/javascript' src='https://binary-butterfly.de/mein/tolles/javascript.js'>
  </body>
</html>

Dies wäre der perfekte Weg: einerseits hat der Browser ganz am Anfang schon die wichtigen CSS-Regeln, um den gerenderten Inhalten von Anfang an eine Struktur und ein recht brauchbares Aussehen zu geben, andererseits muss der Browser nichts warten, da die Detail-Regeln erst nach den Inhalten geladen werden.

Das Problem an diesem Weg ist nur: auf modernen, komplexeren Seiten lassen sich wichtige und unwichtige CSS-Regeln nicht voneinander trennen. Das gilt erst Recht für CMS oder Blog-Systeme wie WordPress. Daher:

Der pragmatische, sinnvolle Weg

Der pragmatische Weg versehentliches Reduzieren der Geschwindigkeit durch massenhaften Inline-Code ist daher die ganz am Anfang vorgestellte Variante: CSS als externe Datei in den Kopfbereich, JavaScript in den Fußbereich. Um dies zu erreichen, machen Plugins wie Autoptimize Sinn, ebenso wie die in umfangreichen Caching-Plugins wie W3 Total Cache oder WP Rocket integrierten Minification-Funktionalitäten Sinn machen.

Wichtig ist nur, dass man die CSS im HTML Head behält; beachtet man dies, ist das Zusammenfassen von CSS-Dateien recht gefahrenlos. Die Scripte kann man getrost in den Fussbereich schieben, dort muss man nur aufpassen, dass es zu keinen JavaScript-Fehlern kommt. Anfänger sollten daher von der JavaScript-Minification Abstand nehmen. [UPDATE]Alternativ können Scripte natürlich auch asynchron geladen werden, das hat am Ende denselben Effekt. In manchen, sehr, sehr seltenen Fällen ist das asynchrone Laden sogar vorteilhaft, wie z.B. bei Analytics, wenn einem die Anzahl der abgebrochenen Seiten-Ladevorgänge wichtig ist.[/UPDATE]

Am Ende bedeutet das, dass man auf einige PageSpeed-Punkte verzichten muss, wenn man den technisch sinnvollen Weg gehen will. Aber das sollte es einem Wert sein, schließlich möchte man seinem Nutzer ja eine gute Seite bieten, nicht Google. Zumal Google auch einfach keine Fleißbienchen-Punkte verteilt, nur weil man jeden einzelnen Punkt in PageSpeed erfüllt hat. Wenn es technisch sinnvoll ist, dann kann man durchaus auch einen vermeintlichen Fehler drin lassen.

Dies gilt im übrigen für jede Form von Tools: hört auf, Euch panisch zu machen wegen irgendwelcher automatisierten Analysen. Automatik-Analysen haben ihre Grenzen. Das heisst nicht, dass derartige Automatik-Analyse-Tools sinnlos sind. Aber Ihr seid es, die die Ergebnisse interpretieren müsst. Euer Kopf muss das verstehen, die dahinter liegenden Probleme (sofern vorhanden) identifizieren und beseitigen. Das kann nur ein menschlicher Kopf machen. Das Tool hilft euch nur, mehr Daten für eine gute Entscheidung zu bekommen. Mehr nicht.

18 Antworten zu “Warum 100 PageSpeed-Punkte oft nicht erstrebenswert sind”

  1. Schöner Artikel!
    Ich persönlich derigister/register die JS-Dateien nicht neu, sondern lade sie meistens mit „defer“ am Schluss.

    So aus dem Bauch heraus ist deine Lösung wahrscheinlich „sauberer“ oder?

    Hier mal ein Beispiel von meinem Lösungsweg:
    add_filter( ‚clean_url‘, function( $url )
    {
    if ( FALSE === strpos( $url, ‚jquery-migrate.min.js‘ ))
    { // not our file
    return $url;
    }
    // Must be a ‚, not „!
    return „$url‘ defer=’defer“;
    }, 11, 1 );

    • Hatte das zwischenzeitlich ergänzt, dass asynchrones Laden natürlich auch ein sinniger Weg ist, ganz besonders auch bei Analytics. Läuft am Ende ja aufs selbe hinaus. Mein Weg ist stupider weil er ohne Manipulation der Ausgabe auskommt, aber das ist am Ende egal.

  2. „hört auf, Euch panisch zu machen wegen irgendwelcher automatisierten Analysen.“
    Das predige ich auch immer meinen Kunden. Nur weil ein Tool meckert heißt es noch lange nicht das die Seite langsam ist.

  3. Was muss ich denn bei dem jquery Script statt „BINARY_BUTTERFLY_VERSION“ setzen, um es an meine Seite anzupassen?

    Gruß

    Hansjörg

      • Danke. Aber ich muss nochmal nachfragen. Bei mir führt der o.g. Code zwar zum Verschieben von wp-includes/js/jquery/jquery-migrate.min.js, nicht aber von wp-includes/js/jquery/jquery.js. Letztere verbleibt im Header.

        • Dann sorgt irgendeine Dependency bei dir dafür, dass jQuery oben bleibt. Schau dir also deine JavaScripts an, schaue genauer hin, welche Scripts eine jQuery Dependency haben und ob diese im Header geladen werden. Vermutlich darfst du also noch weitere Scripte in den Footer schieben.

  4. Ich gehe mit den Schlussfolgerungen es Artikels einig.

    Hat es aber nicht Priorität, dass ich bei Google möglichst vorne gelistet bin um an möglichst viele Kunden zu kommen?

    Dann hat „Google Pagespeed“ Priorität – oder nicht?

    • Da es keine Bonuspunkte für die Plazierung gibt, wenn man 100 Punkte erreicht hat, hat das eben keine Priorität. Es gibt keine Fleißbienchen bei Google.
      Beim Ranking spielen sehr, sehr viele Faktoren eine Rolle, unter anderem eben auch die Nutzererfahrung. Deine eigene Seite ist da ein ganz gutes Beispiel, wie man überoptimiert: du hast ein recht offensichtliches flash of unstyled content, weil du die CSS im Footer lädst und daher deine Inhalte kurz komplett ohne Styling aufflackern. Kann man machen, ist aber hässlich und verschreckt daher Menschen. Und es bringt halt nix fürs Ranking.

  5. „Da es keine Bonuspunkte für die Plazierung gibt […] Es gibt keine Fleißbienchen bei Google. […] bringt halt nix fürs Ranking“

    Gibt es hierzu eine belastbare Quelle? Ich kann mir nur schwer vorstellen, dass Google ein Tool veröffentlicht, das diverse Fehler (aus Googles Sicht) aufzeigt, ohne dass diese Fehler einen Einfluss aufs Ranking haben. Sicherlich wird man nicht nur durch blockierendes CSS von Platz 1 auf Platz 100 abrutschen, aber dass das überhaupt keinen Einfluss haben soll mag ich nicht so recht glauben.

    „und eine ungestylte Seite ist nun sicherlich nicht nutzbar“

    Doch, zumindest sollte sie nutzbar sein – das ist einer der Hauptpunkte von PageSpeed Insights. Scheußlich und mit FOUC/FOUT: Ja, da kann ich nicht widersprechen; Hier muss man abwägen, ob man das tatsächlich in Kauf nehmen möchte. Aber dennoch „nutzbar“ im Sinne von: „Der Besucher kann schnellstmöglich anfangen zu lesen bzw. bekommt die Inhalte präsentiert, während er auf den Rest wartet.“ Genau darum gehts Google, und eben dies sollte bei einer gut gemachten Website bzw. „sauberem“, ordentlich strukturiertem HTML ohne CSS und JS möglich sein.

    • Gegen das Fleißbienchen sprechen gleich mehrere Sachen:
      – ich habe noch nie von einer Seite gehört, die durch die Verbesserung der letzten paar Prozente irgendwelche Vorteile gehabt hätte
      – Google verhindert mit seinen eigenen Tools aktiv, dass man 100 Punkte erreicht. Beispielsweise sorgt Analytics ohne dreckige Tricks dafür, dass die 100 Punkte nicht erreicht werden. Und das aus gutem Grund, da es gefährlich wäre, dort einen langen Caching-Wert enzustellen. Also honoriert Google offensichtlich technische Gründe gegenüber einer Punktewertung
      – den Aufwand, den man in die letzten paar Punkte steckt, kann man erheblich besser n guten Content stecken. Da hat man ganz erheblich viel mehr von.
      Zu der Nicht-Nutzbarkeit: nun, auch das ist nicht mehr so ganz richtig:
      – Google führt mittlerweile JavaScript aus und rendered die komplette Seite. Sie sagen explizit, dass das ok ist, Inhalte via JS auszuliefern. Deswegen kann es nicht mehr das Ziel sein, eine Seite ohne Assets zu laden
      – ich bin zwar ein großer Fan von strukturiertem HTML, wie man an meinen Flask-Projekten sieht, aber das ist ja nu mal nicht die Realität da draussen, und ich kenne auch kein Projekt, was Bonuspunkte durch ultrasauberes HTML bekommen hätte (auch wenn ich das manchmal sinnvoll fände). Es sagt halt am Ende doch kaum etwas über die Qualität der Website aus
      – Der Nutzer kann selten direkt anfangen zu lesen, wenn die Inhalte herumspringen. Ausserdem ist das aus UI-Sicht nun mal schlicht grauenvoll, und es geht ja auch durchaus darum, dem Nutzer ein optimales Erlebnis zu bieten (und das sag ich als Backendler … oje 😀 )

  6. Was mir in letzter Zeit auch auf die Nerven ging, ist das CF7 seine JS und CSS Dateien auf jeder Seite lädt, egal ob ein Formular vorhanden ist oder nicht.
    Aber die Lösung war schnell parat:

    Einfach beides über die functions rausschmeissen:
    add_filter( ‚wpcf7_load_js‘, ‚__return_false‘ );
    add_filter( ‚wpcf7_load_css‘, ‚__return_false‘ );

    Page-Template anlegen und wieder die Dateien laden

    if ( function_exists( ‚wpcf7_enqueue_scripts‘ ) ) {
    wpcf7_enqueue_scripts();
    }

    if ( function_exists( ‚wpcf7_enqueue_styles‘ ) ) {
    wpcf7_enqueue_styles();
    }

    Verstehe nur nicht warum CF7 nicht gleich so programmiert ist,
    dass die Dateien nur auf Seiten geladen werden, wo auch ein Formular ist.
    Technisch jetzt nicht wirklich aufregend.

  7. Sehr guter Beitrag, Ernesto! Ihr Artikel räumt mit einigen Mythen auf. Ich habe das so geballt noch nirgendwo gelesen.

    Noch ein Argument gegen „sämtliche CSS-Regeln inline“: Es dürfte die Bounce-Rate senken, wenn die Seiten schneller laden. Deswegen habe auch ich mich schweren Herzens entschieden, mein CSS (> 500 KB!) extern einzubinden.

    Vielleicht könnte man noch einen Punkt ergänzen, zum Thema „Antwortzeit des Servers reduzieren“:

    Welche Rolle spielt da eigentlich der Serverstandort?

    Also, ich habe meinen Server in Deutschland, will deutschsprachige Nutzer ansprechen – Google crawlt aber von Kalifornien aus. Ergebnis:

    In Deutschland lädt die Seite schnell (gut für die Zielgruppe) – von Kalifornien aus aber langsam (egal für die deutschen Nutzer, aber schlechte Werte bei Google).

    Konkret nennt mir das Sucuri-Tool folgende Werte für Time to first byte:

    0,244 Sekunden in Deutschland (Frankfurt)

    1,063 Sekunden in Kalifornien (Los Angeles)

    Sollte ich deswegen meinem Provider kündigen und nach USA umziehen?

    Das gäbe tolle Werte bei Google – aber die deutschen Nutzer müssten etwas länger warten, bis die Seite lädt.

    Auch das ist doch so ein Punkt, warum 100 PageSpeed-Punkte oft nicht erstrebenswert sind (oder liege ich da falsch, rechnet Google die Latenz heraus)?

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.