Annotating Your (Critical) CSS

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der folgende Beitrag ist ein Gastbeitrag von Wladston Ferreira Filho. Wir haben Critical CSS bereits behandelt, aber die hier vorgestellte Technik war spezifisch für SCSS. Hier behandelt Wladston die Grundlagen und stellt eine weitere Methode über PostCSS vor, und zeigt ein Beispiel (mit Daten) des Ergebnisses.

Critical CSS ist ein effektiver, aber allzu selten genutzter Ansatz zur Verbesserung der Seitenladeleistung. Critical CSS ist zwei Dinge zusammen:

  1. Verzögertes Laden des Haupt-Stylesheets
  2. Einbettung der wichtigsten Stile ("above the fold")

Die Implementierung von Critical CSS erfordert einige Arbeit. Zum einen bedeutet es, das CSS in zwei Teile zu trennen (die kritischen Teile und den Rest), was ein Wartungsproblem darstellen kann.

Später in diesem Artikel werden wir uns ein Werkzeug ansehen, um diesem Nachteil entgegenzuwirken, indem wir CSS automatisch basierend auf Annotationen (d. h. /* Kommentare */) in der Haupt-CSS-Datei aufteilen.

The Facts

Forschungen von Mozilla, Akamai und vielen anderen Quellen bestätigen: geringe Änderungen in der Seitenladezeit können Leistungskennzahlen erheblich beeinflussen. Bei schlechter Netzwerkverbindung wird die Seitenleistung noch wichtiger, da die Downloadzeiten um ein Vielfaches höher sein können.

Google bietet sogar einen Dienst an, um Seiten eine "Geschwindigkeitsbewertung" zu geben, ein nicht so subtiler Hinweis darauf, dass die Leistung mit der Suchmaschinenoptimierung zusammenhängen kann. Die richtige Anwendung von Critical CSS wird von Google *empfohlen*, um Ihren Score zu verbessern. Die Technik wird mit Sicherheit einen positiven Effekt auf die Rendergeschwindigkeit haben. Die Reduzierung der Renderzeit hängt davon ab, wie klein Sie Ihr Critical CSS machen können und wie groß Ihr Haupt-Stylesheet ist.

Wie Critical CSS funktioniert

Der "normale" Ansatz für CSS besteht darin, Ihr Haupt-Stylesheet als <link> im <head> einzufügen. Der Download und das Parsen davon *blockieren das Rendering*. Critical CSS lässt Ihre Seite schneller rendern, indem es *dieses Blocking umgeht*.

Der erste Schritt besteht darin, die wesentlichen CSS-Regeln, die zum Rendern des Inhalts "above the fold" (oberhalb des sichtbaren Bereichs) der Seite benötigt werden, zu "inlinen" (ein gestraffter <style>-Tag im <head>). Dies ermöglicht den zweiten Schritt: Nicht-kritische CSS-Regeln können *asynchron* (nicht blockierend) geladen werden, während die Webseite gerendert wird. Sobald die große CSS-Datei angekommen ist, wird sie von JavaScript an die Seite angehängt.

Eine gängige Methode, dies in die Praxis umzusetzen, ist die Verwendung eines CSS-Präprozessors. Der Präprozessor kann speziell formatierte Kommentare im CSS erkennen, sodass er das kritische CSS unterscheiden und automatisch trennen kann. Dies wurde bereits auf CSS-Tricks behandelt, mit SCSS. Lassen Sie uns dies in nativer CSS-Syntax untersuchen.

Hinweis: Um dies zum Laufen zu bringen, benötigen Sie ein serverseitiges Werkzeug, um das kritische CSS in alle Seiten einzubetten, die Sie ausliefern, sowie einige Zeilen Inline-JavaScript, um das Haupt-Stylesheet (nicht-kritisch) zu laden.

Bestehende Techniken für Critical CSS

Critical CSS erfordert letztendlich zwei separate CSS-Teile: kritische und nicht-kritische. Wie bekommen wir sie?

Volle manuelle Wartung: Zwei CSS-Dateien pflegen

Bei dieser Strategie bearbeiten Sie direkt zwei CSS-Dateien anstelle einer. Während diese Strategie einfach ist und kein Werkzeug erfordert, ist sie viel schwieriger zu handhaben. Es ist schwieriger, Stile zu verstehen, zu lesen und zu ändern. Sie wird nur für statisches CSS empfohlen, das sich wahrscheinlich nie ändern wird.

Vollautomatisierung

Serverseitige Tools (wie die Google Page Speed Extension) erkennen automatisch, welches Ihrer CSS für das Rendern des Inhalts "above the fold" benötigt wird, und trennen das als kritisch eingestufte CSS und binden es für Sie ein, ohne Ihr Zutun.

Diese Technik hat einige Nachteile: Das automatisch generierte nicht-kritische CSS ändert sich wahrscheinlich für jede ausgewertete Seite, was die Effizienz des CSS-Cachings verringert. Außerdem wird das Critical CSS nicht fehlerfrei erkannt, insbesondere für kleine Bildschirme.

Darüber hinaus haben Sie keine Möglichkeit, den Prozess anzupassen oder fein abzustimmen.

SCSS mit Jacket-Plugin

Wenn Sie SCSS verwenden, können Sie das Jacket-Plugin installieren (Details hier). Jacket trennt CSS, das mit einer speziellen kritischen Klasse markiert ist, in eine separate Datei und generiert nach der Verarbeitung des LCSS kritische und nicht-kritische CSS-Dateien. Das Problem bei dieser Technik ist, dass sie Sie an SCSS bindet. Wenn Sie sich entscheiden, es nicht mehr zu verwenden oder wenn Sie Ihre Präprozessor-Sprache ändern möchten, müssen Sie zusätzliche Arbeit leisten, um Ihre Critical-CSS-Lösung anzupassen.

Meine Technik: PostCSS und PostCSS-Split

Meine Technik beruht darauf, alle Ihre Critical-CSS-Deklarationen mit einfachen, reinen CSS-Kommentaren zu markieren. Betrachten wir dieses super einfache HTML zur Veranschaulichung

<!DOCTYPE html>
<html lang="en">
<body>
  <header>
    <h1>I'm a big header</h1>
  </header>
  <p>I'm below the fold</p></body>
</body>
</html>
header > h1 { 
  /* !Critical */ margin: 300px;
}
p { 
  border: 1px dotted black;
}

Der erste Schritt ist die Markierung der CSS-Regeln, die zum Rendern des Inhalts "above the fold" benötigt werden, indem /* !Critical */ darin platziert wird.

Um herauszufinden, welche Deklarationen aus Ihrem Haupt-Stylesheet in Ihrem kritischen CSS enthalten sein sollen, können Sie Vorschläge von kostenlosen Diensten wie diesem erhalten.

Sobald Sie Ihre Basis-CSS-Datei mit "kritischen" Kommentaren haben, installieren Sie PostCSS-Split mit npm. Sie müssen Node.js installieren, falls Sie das noch nicht getan haben. Geben Sie in einem Terminal diesen Befehl ein, um PostCSS-Split zu installieren

sudo npm install -g postcss-split

Dann können Sie diesen Befehl ausführen und Ihre kommentierte Basis-CSS-Datei an PostCSS-Split übergeben

postcss-split base.css

Brandneue Dateien base-critical.css und base-non-critical.css werden basierend auf Ihrer Eingabedatei erstellt. Der Inhalt von `base-critical.css` soll im <head> in einem <style>-Tag eingefügt werden.

Zum Laden von `base-non-critical.css` können Sie einen asynchronen CSS-Loader verwenden. Fügen Sie zum Beispiel Folgendes vor dem </body>-Tag ein (und ändern Sie <your_css_url> entsprechend)

<script>
function lCss(u, m) {
  var l = document.createElement('link');
  l.rel = 'stylesheet';
  l.type = 'text/css';
  l.href = u;
  l.media = m;
  document.getElementsByTagName('head')[0].appendChild(l)
}
function dCss() {
  lCss('<your_css_url>', 'all')
}
if (window.addEventListener) {
  window.addEventListener('DOMContentLoaded', dCss, false)
} else { 
  window.onload=dCss
}
</script>

Potenzielle Fallstricke jeder Critical-CSS-Technik

Wenn Sie eine beliebige Critical-CSS-Technik verwenden, werden Sie wahrscheinlich auf einige Probleme stoßen. Sehen wir uns an, wie wir ihnen begegnen können

Präzedenz

Wenn Sie mehrere CSS-Regeln mit der gleichen Spezifität haben, werden später deklarierte Regeln Vorrang vor früher deklarierten Regeln haben.

Beachten Sie, dass sich die von Ihnen als kritisch bezeichneten CSS-Regeln ihren Speicherort ändern: Sie werden in Ihrem <head> inline sein, was bedeutet, dass sie zuerst geladen werden und von später geladenem CSS mit Selektoren gleicher Spezifität überschrieben werden.

Wenn Sie Probleme haben, Ihre korrekten CSS-Stile mit Critical CSS auf diese Weise zu erhalten, stellen Sie sicher, dass Ihr CSS nicht von der Reihenfolge abhängt. Wenn Sie seltsame Ergebnisse erhalten, verwenden Sie einen CSS-Inspektor, um Ihnen zu helfen, Ihre Spezifitätsprobleme zu beheben.

FOUC

Wenn Ihr Critical CSS nicht *jede* Regel enthält, die zum Rendern des gesamten Inhalts "above the fold" benötigt wird, oder wenn Ihr Benutzer beginnt, den Inhalt unterhalb des sichtbaren Bereichs zu durchsuchen, bevor der Großteil Ihres CSS geladen ist, erleben Sie den FOUC-Effekt (Flash of Unstyled Content).

Wenn Ihr nicht-kritisches CSS geladen wird, ändert der Browser die Stile Ihrer Seite, um die Regeln aus dem nicht-kritischen CSS anzuwenden. Dieser "Blitz" der Stiländerung kann unerwünscht sein.

Eine Möglichkeit, diese Peinlichkeit zu mildern, ist die Verwendung von CSS-<a href="https://css-tricks.de/almanac/properties/t/transition/">Übergängen</a>, um sanft von ungestylt zu gestylt zu wechseln. Während der Entwicklung können Sie dem JavaScript-Code, der Ihr Bulk-CSS injiziert, manuell eine Verzögerung hinzufügen.

Einbinden des Critical CSS in die HTML-Seiten

Sie benötigen ein Werkzeug, um das Critical CSS in den <head> Ihrer HTML-Seiten zu injizieren. Wenn Sie eine serverseitige Sprache wie PHP verwenden, können Sie dies einfach mit einer include()-Anweisung (oder ähnlich) tun.

<!DOCTYPE html>
<html lang="en">

<head>

  ...

  <style>
    <?php include_once("/path/to/base-critical.css"); ?>
  </style>

  ...

Wenn Sie nicht direkt mit dem Code arbeiten (z. B. wenn Sie ein Content-Management-System wie WordPress verwenden), können Sie nach einer Konfigurationseinstellung oder einem Plugin suchen, das dies für Sie erledigt. In WordPress können Sie einen "Hook" hinzufügen, um den Inhalt Ihrer CSS-Datei in Ihr finales HTML einzubetten.

Jeremy Keith hat einen Weg mit Grunt/Twig umrissen.

Ist es das wirklich wert?

Zusammenfassend…

Dies sind die Schritte zur Implementierung dieser Technik

  • Identifizieren und markieren Sie Ihr Critical CSS in Ihrem Haupt-Stylesheet.
  • Fügen Sie Ihrer Bereitstellungsroutine eine Aufgabe hinzu, um die Basis-CSS-Datei in zwei Dateien aufzuteilen.
  • Fügen Sie den zusätzlichen JavaScript-Code hinzu, um Ihr Haupt-Stylesheet asynchron zu laden.
  • Implementieren Sie eine serverseitige Include-Funktion, um den Inhalt Ihres Critical CSS in den <head> jeder Seite einzufügen.

Fallstudie: Reale Website mit Critical CSS

Ich habe die Website https://code.energy so programmiert, dass sie Seiten mit oder ohne Critical CSS ausliefern kann. Sie verwendet standardmäßig Critical CSS, es sei denn, eine Abfragezeichenfolge nocritical wird hinzugefügt (Beispiel: https://code.energy?nocritical). Eine weitere Möglichkeit, Critical CSS zu deaktivieren, ist die Übergabe eines User-Agent-Headers, der die Zeichenfolge nocritical enthält.

Damit können wir leicht messen, wie Critical CSS die Geschwindigkeit Leistung dieser Website mit Online-Tools wie webpagetest.org beeinflusst. Webpagetest ermöglicht das einfache Ausführen von Tests mit einer benutzerdefinierten User-Agent-Zeichenfolge. Dies sind die Ergebnisse des Durchschnitts von 5 Experimenten für jedes Szenario

Kritisch Ladezeit Start Rendering Vollständiges Laden Speed Idx
x 0,949s 0,988s 1,003s 1036
0,838s 0,695s 0,893s 755

Der beeindruckendste Unterschied ist die "Start Render"-Zeit. Durch das asynchrone Laden des CSS kann der Browser mehr Anfragen parallel ausführen, da er viel früher mit dem Parsen des HTML beginnt, wie hier zu sehen ist

Fazit

Wenn Sie die bestmögliche Leistung für Ihre Website wünschen, benötigen Sie eine Critical-CSS-Strategie. Und mit PostCSS-Split können Sie diese mit geringem Wartungsaufwand erhalten.