Was tun, wenn CSS das Parsen von Seiten blockiert?

Kürzlich habe ich eine Prüfung eines Standorts durchgeführt und preload/polyfillbin auf ein Muster gestoßen , das ich bereits bei mehreren Kunden gesehen habe. Die Verwendung dieses zuvor beliebten Musters wird heute nicht empfohlen. Es ist jedoch nützlich, dies zu berücksichtigen, um die Bedeutung einer sorgfältigen Verwendung des Mechanismus zum Vorladen von Materialien durch Webbrowser zu veranschaulichen. Es ist auch interessant, weil Sie damit ein reales Beispiel dafür zeigen können, wie sich die Reihenfolge der Elemente in einem Dokument auf die Leistung auswirken kann (dies wird in diesem wunderbaren Artikel von Harry Roberts behandelt). Das Material, dessen Übersetzung wir heute veröffentlichen, widmet sich der Analyse von Situationen, in denen ein unsachgemäßer und vorzeitiger Umgang mit CSS-Ressourcen die Leistung von Webseiten beeinträchtigt.





Über loadCSS


Ich bin ein großer Fan der Filament Group - sie veröffentlichen unglaublich viele großartige Projekte. Darüber hinaus erstellen sie ständig unschätzbare Tools und teilen diese, um das Web zu verbessern. Eines dieser Tools ist loadCSS , das lange Zeit genau das Tool war, das ich jedem zum Laden unkritischer CSS-Ressourcen empfohlen habe.

Obwohl sich dies jetzt geändert hat (und die Filament Group einen ausgezeichneten Artikel darüber veröffentlicht hat, was ihre Mitarbeiter heutzutage bevorzugen), sehe ich bei der Prüfung von Websites häufig, wie sie loadCSSdiese in der Produktion verwenden.

Eines der Muster, auf die ich gestoßen bin, ist das Musterpreload/polyfill. Bei diesem Ansatz werden alle Dateien mit Stilen im Preload-Modus geladen (das Attribut der relentsprechenden Links wird auf gesetzt preload). Wenden Sie danach, wenn sie einsatzbereit sind, ihre Ereignisse onloadan, um sie mit der Seite zu verbinden.

<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="path/to/mystylesheet.css"></noscript>

Da nicht alle Browser das Design unterstützen, <a href="https://caniuse.com/#feat=link-rel-preload"><link rel="preload"></a>bietet das Projekt loadCSSEntwicklern eine praktische Polyfüllung, die der Seite nach der Beschreibung der relevanten Links hinzugefügt wird:

<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
<noscript>
    <link rel="stylesheet" href="path/to/mystylesheet.css">
</noscript>
<script>
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
(function(){ ... }());
</script>

Störung der Netzwerkprioritäten


Ich war noch nie ein begeisterter Fan dieses Musters. Das Vorladen ist ein unhöfliches Werkzeug. Materialien, die über Attributlinks heruntergeladen wurden, rel="preload"kämpfen erfolgreich mit anderen Materialien um Netzwerkressourcen. Bei der Verwendung wird preloaddavon ausgegangen, dass Stylesheets, die asynchron geladen werden, weil sie bei der Ausgabe einer Seite keine entscheidende Rolle spielen, von Browsern eine sehr hohe Priorität erhalten.

Das folgende Bild aus WebPageTest zeigt dieses Problem sehr gut. In den Zeilen 3-6 sehen Sie das asynchrone Laden von CSS-Dateien anhand eines Musters preload. Obwohl Entwickler diese Dateien für nicht so wichtig halten, dass das Herunterladen das Rendern blockieren würde, sollten Sie sie verwendenpreload bedeutet, dass sie geladen werden, bevor der Browser die verbleibenden Ressourcen erhält.


CSS-Dateien, die beim Laden das Preload-Muster verwenden, kommen früher als andere Ressourcen im Browser an, obwohl es sich nicht um Ressourcen handelt, die für das anfängliche Rendern einer Seite von entscheidender Bedeutung sind

HTML-Parser-Sperre


Die mit der Priorität des Ladens von Ressourcen verbundenen Probleme reichen bereits aus, um die Verwendung des Musters in den meisten Situationen zu vermeiden preload. In diesem Fall wird die Situation jedoch durch das Vorhandensein eines anderen Stylesheets verschärft, das auf die übliche Weise geladen wird.

<link rel="stylesheet" href="path/to/main.css" />
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
<noscript>
    <link rel="stylesheet" href="path/to/mystylesheet.css">
</noscript>
<script>
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
(function(){ ... }());
</script>

Es gibt die gleichen Probleme bei der Verwendung preload, die dazu führen, dass nicht die wichtigsten Dateien eine hohe Priorität erhalten. Genauso wichtig und vielleicht weniger offensichtlich ist jedoch, welche Auswirkungen dies auf die Fähigkeit des Browsers hat, die Seite zu analysieren.

Auch hier hat dies bereits geschrieben im Detail , so empfehle ich, besser zu verstehen , dass das Material , um zu lesen , was geschieht. Hier werde ich kurz darauf eingehen.

In der Regel blockiert das Laden von Stilen das Rendern von Seiten. Der Browser muss Stile abfragen und analysieren, um die Seite anzeigen zu können. Dies hindert den Browser jedoch nicht daran, den Rest des HTML-Codes zu analysieren.

Skripte blockieren dagegen den Parser, wenn sie nicht als deferoder markiert sind async.

Da der Browser davon ausgehen muss, dass das Skript entweder den Inhalt der Seite selbst oder die darauf angewendeten Stile manipuliert, muss er vorsichtig sein, wann dieses Skript ausgeführt wird. Wenn der Browser weiß, dass CSS-Code geladen wird, wartet er auf das Eintreffen dieses CSS-Codes und führt anschließend das Skript aus. Und da der Browser das Dokument erst dann weiter analysieren kann, wenn das Skript ausgeführt wird, bedeutet dies, dass die Stile nicht mehr nur das Rendern blockieren. Sie verhindern, dass der Browser HTML analysiert.

Dieses Verhalten gilt sowohl für externe als auch für in die Seite eingebettete Skripte. Wenn CSS geladen wird, werden Inline-Skripte erst ausgeführt, wenn dieses CSS im Browser eintrifft.

Problemstudie


Der verständlichste Weg, um dieses Problem zu visualisieren, ist die Verwendung der Chrome-Entwicklertools (mir gefällt das Niveau, auf das diese Tools angewachsen sind).

Unter den Chrome-Tools gibt es eine Registerkarte, Performancemit der Sie das Seitenladeprofil aufzeichnen können. Ich empfehle, die Netzwerkverbindung künstlich zu verlangsamen, damit sich das Problem besser manifestiert.

In diesem Fall habe ich mit dem Fast 3G-Netzwerk-Setup getestet. Wenn Sie sich genau ansehen, was mit dem Hauptthread passiert, können Sie verstehen, dass die Anforderung zum Laden der CSS-Datei ganz am Anfang der HTML-Analyse erfolgt (ca. 1,7 Sekunden, nachdem die Seite geladen wurde).


Ein kleines Rechteck unter dem HTML-Analyseblock stellt eine Anforderung zum Empfangen einer CSS-Datei dar.

Während des nächsten Zeitraums, der ungefähr eine Sekunde beträgt, ist der Hauptthread inaktiv. Hier sehen Sie kleine Aktivitätsinseln. Dies ist ein Auslösen von Ereignissen, die den Abschluss des Ladens von Stilen anzeigen, und das Senden von Ressourcen anderer Anforderungen durch den Vorlademechanismus. Der Browser hört jedoch vollständig auf, HTML zu analysieren.


Wenn Sie sich das Gesamtbild ansehen, stellt sich heraus, dass der Hauptthread nach dem Start des CSS-Ladevorgangs länger als 1,1 Sekunden inaktiv ist. Nach

2,8 Sekunden wird der Stil geladen und vom Browser verarbeitet. Erst dann sehen wir die Verarbeitung des eingebauten Skripts, und danach kehrt der Browser schließlich zur HTML-Analyse zurück.


CSS kommt in ungefähr 2,8 Sekunden an. Danach sehen wir, dass der Browser weiterhin HTML analysiert

Firefox ist eine schöne Ausnahme


Das obige Verhalten ist für Chrome, Edge und Safari üblich. Firefox ist eine schöne Ausnahme von der Liste der beliebtesten Browser.

Alle anderen Browser unterbrechen die HTML-Analyse, verwenden jedoch einen proaktiven Parser (ein Mittel zum Vorladen von Materialien), um den Code für Links zu externen Ressourcen anzuzeigen und Anforderungen zum Laden dieser Ressourcen zu erfüllen. Firefox geht jedoch noch einen Schritt weiter in dieser Angelegenheit: es spekulativ baut einen DOM - Baum, auch wenn es das Skript erwartet auszuführen.

Sofern das Skript das DOM nicht manipuliert, was dazu führt, dass die Ergebnisse der spekulativen Analyse verworfen werden müssen, kann Firefox diesen Ansatz nutzen. Wenn der Browser den spekulativ erstellten DOM-Baum löschen muss, bedeutet dies natürlich, dass er beim Erstellen dieses Baums nichts Nützliches getan hat.

Dies ist ein interessanter Ansatz. Ich war furchtbar neugierig zu wissen, wie effektiv es ist. Jetzt gibt es jedoch keine Informationen dazu im Firefox Performance Profiler. Dort können Sie nicht herausfinden, ob der spekulative Parser funktioniert hat, ob die von ihm geleistete Arbeit wiederholt werden muss und ob sich dies noch auf die Leistung auswirkt.

Ich habe mit denen gesprochen, die für die Firefox-Entwicklertools verantwortlich sind, und ich kann sagen, dass sie interessante Ideen haben, wie solche Informationen in Zukunft im Profiler dargestellt werden können. Ich hoffe sie haben Erfolg.

Lösung


Im Fall des Clients, den ich ganz am Anfang erwähnte, sah der erste Schritt zur Lösung dieses Problems äußerst einfach aus: Entfernen Sie das Muster preload/polyfill. Das Vorladen von unkritischem CSS ist sinnlos. Hier müssen Sie zur Verwendung rel="preload"eines Attributs anstelle eines Attributs wechseln media="print". Genau das empfehlen die Experten der Filament Group. Dieser Ansatz ermöglicht es Ihnen außerdem, die Polyfüllung vollständig zu entfernen.

<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">

Dies bringt uns bereits in eine bessere Position: Jetzt sind die Netzwerkprioritäten viel besser auf die tatsächliche Bedeutung der Downloads abgestimmt. Und wir werden auch das eingebaute Skript los.

In diesem Fall befindet sich im Dokumentenkopf unterhalb der Zeile, die die Anforderung zum Laden von CSS initiiert, noch ein weiteres integriertes Skript. Wenn Sie dieses Skript so verschieben, dass es sich vor der Zeile befindet, in der das CSS geladen wird, wird die Parser-Sperre aufgehoben. Wenn Sie die Seite erneut mit den Chrome Developer Tools analysieren, ist der Unterschied völlig offensichtlich.


Bevor Änderungen am Seitencode vorgenommen wurden, hielt der HTML-Parser in Zeile 1939 an, nachdem er auf ein integriertes Skript gestoßen war, und blieb etwa eine Sekunde hier. Nach der Optimierung konnte er auf Zeile 5281 zugreifen.

Früher wurde der Parser in Zeile 1939 angehalten und auf das Laden von CSS gewartet. Jetzt erreicht er Zeile 5281. Dort befindet sich am Ende der Seite ein weiteres integriertes Skript, das den Parser erneut stoppt.

Dies ist eine schnelle Lösung für das Problem. Dies ist nicht die Option, die die endgültige Lösung des Problems darstellt. Das Ändern der Reihenfolge der Elemente und das Entfernen des Musterspreload/polyfillist nur der erste Schritt. Sie können dieses Problem am besten lösen, indem Sie kritischen CSS-Code in eine Seite einbetten, anstatt ihn aus einer externen Datei zu laden. Musterpreload/polyfillEntwickelt, um zusätzlich zu Inline-CSS verwendet zu werden. Auf diese Weise können wir die mit Skripten verbundenen Probleme vollständig ignorieren und sicherstellen, dass der Browser nach Ausführung der ersten Anforderung über alle zum Rendern der Seite erforderlichen Stile verfügt.

Im Moment sollte jedoch beachtet werden, dass wir eine gute Leistungssteigerung erzielen können, indem wir sehr kleine Änderungen am Projekt in Bezug auf die Art und Weise, wie Stile geladen werden, und die Reihenfolge der Elemente im DOM vornehmen.

Zusammenfassung


  • Wenn Sie ein loadCSSMuster verwenden preload/polyfill, wechseln Sie zum Muster zum Laden von Stilen print.
  • Wenn Sie externe Stile haben, die auf die übliche Weise geladen werden (dh reguläre Links zu Dateien dieser Stile verwenden), verschieben Sie alle integrierten Skripts, die über die Links verschoben werden können, um Stile zu laden.
  • Betten Sie kritische Stile in die Seite ein, um den schnellstmöglichen Start des Renderns zu gewährleisten.

Liebe Leser! Haben Sie Probleme beim Verlangsamen des Renderns von Seiten aufgrund von CSS festgestellt?

PS
RUVDS gratuliert allen IT-Profis am 8. März!
In diesem Jahr haben wir beschlossen, keine Tulpen zu verschenken und keine Auswahl an Geek-Geschenken zu treffen. Wir sind einen anderen Weg gegangen und haben die IT-Seite für Frauen erstellt , um die Präsenz von IT-Spezialistinnen zu zeigen.


All Articles