So laden Sie CSS asynchron

93

Ich versuche, zwei CSS-Dateien zu entfernen, die auf meiner Website gerendert werden. Sie werden in Google Page Speed ​​Insights angezeigt. Ich habe verschiedene Methoden angewendet, von denen keine erfolgreich war. Aber kürzlich habe ich einen Beitrag über Thinking Async gefunden und als ich diesen Code angewendet habe: <script async src="https://third-party.com/resource.js"></script>Er hat das Problem beseitigt.

Nach der Veröffentlichung verlor die Seite jedoch das Styling. Ich bin mir nicht sicher, was los ist, da der Code funktioniert, aber das Styling nach dem Hochladen funktioniert nicht. Würde mich über Ihre Hilfe freuen. Vielen Dank

Paulina994
quelle
2
Wenden Sie Async auf Stile oder Skripte an? Der Stil wird einige Zeit nach dem Laden der Seite geladen oder wird er nie angezeigt?
Kamus
Ich habe das asynchrone Attribut auf Stile angewendet und sie in die Kopfzeile eingefügt.
Paulina994
2
Die Sache mit Stilen ist, dass ein erneutes Rendern ausgelöst wird, wenn Sie sie spät laden (z. B. im Körper) und in den Standards nicht zulässig ist (aber da Browser sehr verzeihend sind, funktioniert es trotzdem). Wenn das Problem langsame Antwortzeiten von einem Server eines Drittanbieters sind, können Sie diese möglicherweise einfach auf Ihrem Server hosten?
Josef Engelfrost

Antworten:

130

Der Trick zum Auslösen eines asynchronen Stylesheet-Downloads besteht darin, ein <link>Element zu verwenden und einen ungültigen Wert für das Medienattribut festzulegen (ich verwende media = "none", aber jeder Wert reicht aus). Wenn eine Medienabfrage als falsch ausgewertet wird, lädt der Browser das Stylesheet weiterhin herunter, wartet jedoch nicht, bis der Inhalt verfügbar ist, bevor die Seite gerendert wird.

<link rel="stylesheet" href="css.css" media="none">

Nach Abschluss des Stylesheets muss das Medienattribut auf einen gültigen Wert festgelegt werden, damit die Stilregeln auf das Dokument angewendet werden. Das Onload-Ereignis wird verwendet, um die Medieneigenschaft auf alle umzuschalten:

<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'">

Diese Methode zum Laden von CSS liefert den Besuchern viel schneller nutzbare Inhalte als der Standardansatz. Kritisches CSS kann weiterhin mit dem üblichen Blockierungsansatz bereitgestellt werden (oder Sie können es für die ultimative Leistung einbinden), und unkritische Stile können nach und nach heruntergeladen und später im Parsing- / Rendering-Prozess angewendet werden.

Diese Technik verwendet JavaScript. Sie können jedoch auch Nicht-JavaScript-Browser berücksichtigen, indem Sie die entsprechenden Blockierungselemente <link>in ein <noscript>Element einschließen:

<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'"><noscript><link rel="stylesheet" href="css.css"></noscript>

Sie können den Vorgang unter www.itcha.edu.sv sehen

Geben Sie hier die Bildbeschreibung ein

Quelle in http://keithclark.co.uk/

Vladimir Salguero
quelle
Ok .. Ich wusste nicht, dass Sie Elementattribute in den On-Handlern referenzieren können, indem Sie nur ihren Namen erwähnen. Ich habe immer gedacht, dass "Ereignis" die einzige Ausnahme ist.
Teemoh
1
Wie verhindern Sie, dass Ihre Seite blinkt, wenn alles neu gerendert wird? Fügen Sie außerdem Kern-App-Shell-Stile ein, damit Ihre Seite ein anfängliches Layout aufweist, anstatt etwas zu rendern, auf das Lynx stolz wäre?
Chris Love
2
Scheint immer noch für mich zu arbeiten. Danach weiß ich, dass in PageSpeed ​​Insights für diese Datei länger eine Warnung angezeigt wird.
AndyWarren
3
das funktioniert bei mir (08-juli -2018). Und es gibt eine gute Punktzahl in Pagespeed Insight
abilash er
1
IMHO, Jabachettas neuere Antwort mit "Preload" , ist jetzt wahrscheinlich die bevorzugte Lösung. Wenn jemand Grund zu der Annahme hat, dass diese Antwort immer noch vorzuziehen ist, fügen Sie bitte einen Kommentar hinzu, in dem erläutert wird, warum. Idealerweise eine Verknüpfung mit einer Ressource, die bestätigt, warum / wann dieser Ansatz noch vorzuziehen ist. [Angenommen, Sie verwenden die Polyfüllung zur Unterstützung preloadvon Firefox und älteren Browsern - siehe Link im ersten Kommentar dieser Antwort].
ToolmakerSteve
114

2020 Update


Die einfache Antwort (volle Browserunterstützung):

<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'">

Die dokumentierte Antwort (mit optionalem Vorladen und fallaktiviertem Skript):

 <!-- Optional, if we want the stylesheet to get preloaded. Note that this line causes stylesheet to get downloaded, but not applied to the page. Use strategically — while preloading will push this resource up the priority list, it may cause more important resources to be pushed down the priority list. This may not be the desired effect for non-critical CSS, depending on other resources your app needs. -->
 <link rel="preload" href="style.css" as="style">

 <!-- Media type (print) doesn't match the current environment, so browser decides it's not that important and loads the stylesheet asynchronously (without delaying page rendering). On load, we change media type so that the stylesheet gets applied to screens. -->
 <link rel="stylesheet" href="style.css" media="print" onload="this.media='all'">

 <!-- Fallback that only gets inserted when JavaScript is disabled, in which case we can't load CSS asynchronously. -->
 <noscript><link rel="stylesheet" href="style.css"></noscript>

Vorladen und Asynchronisieren kombiniert:

Wenn Sie vorinstalliertes und asynchrones CSS benötigen, kombiniert diese Lösung einfach zwei Zeilen aus der oben dokumentierten Antwort, wodurch sie etwas sauberer wird. Dies funktioniert jedoch erst in Firefox, wenn sie das unterstützen Schlüsselwort für Vorladen unterstützt wird . Wie in der oben dokumentierten Antwort ausführlich beschrieben, ist das Vorladen möglicherweise nicht wirklich vorteilhaft.

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

Weitere Überlegungen:

Beachten Sie, dass im Allgemeinen, wenn Sie CSS asynchron laden möchten, empfohlen wird, kritisches CSS zu integrieren , da CSS aus einem bestimmten Grund eine Renderblockierungsressource ist .

Dank an die Filament Group für ihre vielen asynchronen CSS-Lösungen.

Jabacchetta
quelle
3
Es ist nicht erforderlich, loadCSS zu verwenden. Die Polyfüllung reicht aus: github.com/filamentgroup/loadCSS/blob/master/src/…
Nathan
1
Der Spezifikationsstatus von Preload lautet schließlich [W3C Candidate Recommendation]. ( W3.org/TR/preload/… ) Firefox unterstützt ihn, ist jedoch standardmäßig deaktiviert. Klicken Sie auf den Link "Weitgehend unterstützt" der Antwort, um die Beschreibung des Firefox-Flags, das sie steuert, zu "Kann ich verwenden".
ToolmakerSteve
1
Die Antwort wurde aktualisiert, um eine Lösung für die vollständige Browserunterstützung sowie zusätzliche Erklärungen bereitzustellen.
Jabacchetta
1
@jabacchetta das 2020-Update wird sehr geschätzt, danke. Ich habe speziell nach Anweisungen gesucht , die in letzter Zeit geschrieben wurden und bei denen die Browserunterstützung im Allgemeinen besser ist. Vieles ändert sich über 3 Jahre im Web!
Brandito
1
Anscheinend ist es besser zu onload="this.rel='stylesheet'; this.onload = null". Es muss eingestellt werden, this.onloadum nullzu vermeiden, dass dies in einigen Browsern anscheinend zweimal aufgerufen wird.
Flimm
9

Verwenden von media="print"undonload

Die Filamentgruppe hat kürzlich (Juli 2019) einen Artikel veröffentlicht , der ihre neueste Empfehlung zum asynchronen Laden von CSS enthält. Obwohl sie Entwickler der beliebten Javascript-Bibliothek loadCSS sind , empfehlen sie diese Lösung, für die keine Javascript-Bibliothek erforderlich ist:

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

Mit media="print"wird dem Browser angezeigt, dieses Stylesheet nicht auf Bildschirmen, sondern beim Drucken zu verwenden. Browser laden diese Druck-Stylesheets zwar herunter, aber asynchron, was wir wollen. Wir möchten auch, dass das Stylesheet verwendet wird, sobald es heruntergeladen wurde, und dafür legen wir fest onload="this.media='all'; this.onload = null". (Einige Browser rufen onloadzweimal auf, um dies zu umgehen, müssen wir festlegen this.onload = null.) Wenn Sie möchten, können Sie einen <noscript>Fallback für die seltenen Benutzer hinzufügen, für die Javascript nicht aktiviert ist.

Der Originalartikel ist eine Lektüre wert, da er detaillierter ist als ich hier bin. Dieser Artikel auf csswizardry.com ist ebenfalls eine Lektüre wert.

Flimm
quelle
5

Sie können versuchen, es auf viele Arten zu bekommen:

1.Verwenden media="bogus"und ein <link>am Fuß

<head>
    <!-- unimportant nonsense -->
    <link rel="stylesheet" href="style.css" media="bogus">
</head>
<body>
    <!-- other unimportant nonsense, such as content -->
    <link rel="stylesheet" href="style.css">
</body>

2.DOM auf die alte Weise einfügen

<script type="text/javascript">
(function(){
  var bsa = document.createElement('script');
     bsa.type = 'text/javascript';
     bsa.async = true;
     bsa.src = 'https://s3.buysellads.com/ac/bsa.js';
  (document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(bsa);
})();
</script>

3.Wenn Sie Plugins ausprobieren können, können Sie loadCSS ausprobieren

<script>
  // include loadCSS here...
  function loadCSS( href, before, media ){ ... }
  // load a file
  loadCSS( "path/to/mystylesheet.css" );
</script>
Kamus
quelle
3
Beispiel 2 lädt Javascript, aber die Frage betrifft das Laden von CSS. Wissen Sie, ob Beispiel 2 auch für CSS funktioniert, wenn Sie von <script>zu wechseln <style rel=stylesheet>? (Nur neugierig. Ich werde loadCSSstattdessen (dh Ihr Beispiel 3) verwenden, wenn ich später CSS laden muss.)
KajMagnus
5

Mit der folgenden Funktion werden alle Stylesheets erstellt und dem Dokument hinzugefügt, die Sie asynchron laden möchten. (Dank der Funktion Event Listenerwird dies jedoch erst ausgeführt, nachdem alle anderen Ressourcen des Fensters geladen wurden.)

Siehe folgendes:

function loadAsyncStyleSheets() {

    var asyncStyleSheets = [
    '/stylesheets/async-stylesheet-1.css',
    '/stylesheets/async-stylesheet-2.css'
    ];

    for (var i = 0; i < asyncStyleSheets.length; i++) {
        var link = document.createElement('link');
        link.setAttribute('rel', 'stylesheet');
        link.setAttribute('href', asyncStyleSheets[i]);
        document.head.appendChild(link);
    }
}

window.addEventListener('load', loadAsyncStyleSheets, false);
Rounin
quelle
1
Gibt es irgendwelche Nachteile dieser Methode, wenn wir sie beispielsweise mit dem loadCSS-Ansatz vergleichen? Es scheint, dass der klassische Code var newStyle = document.createElement("link"); newStyle.rel = "stylesheet"; newStyle.href = "stylesheet.css"; document.getElementsByTagName("head")[0].appendChild(newStyle);im <script>Tag im Seitenkörper seine Arbeit hervorragend macht - selbst in alten Browsern wie MSIE8.
TecMan
2
@TecMan ja gibt es. Wie Sie sehen können, erledigt diese Funktion ihre Aufgabe bei window.loadEreignissen. Der Download beginnt also, wenn alles heruntergeladen ist. Kein Glück da. Sie müssen das Laden so schnell wie möglich nicht blockieren, um zu starten.
Miloš Đakonović
5

Asynchrone CSS-Ladeansätze

Es gibt verschiedene Möglichkeiten, einen Browser dazu zu bringen, CSS asynchron zu laden, obwohl keine so einfach ist, wie Sie es vielleicht erwarten.

<link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet'">
virender nehra
quelle
1

Wenn Sie einen CSS-Link programmgesteuert und asynchron laden müssen:

// https://www.filamentgroup.com/lab/load-css-simpler/
function loadCSS(href, position) {
  const link = document.createElement('link');
  link.media = 'print';
  link.rel = 'stylesheet';
  link.href = href;
  link.onload = () => { link.media = 'all'; };
  position.parentNode.insertBefore(link, position);
}
Olivier Tassinari
quelle
0

Wenn Sie eine strenge Richtlinie zur Inhaltssicherheit haben , die die Antwort von @ vladimir-salguero nicht zulässt , können Sie diese verwenden (bitte beachten Sie das Skript nonce):

<script nonce="(your nonce)" async>
$(document).ready(function() {
    $('link[media="none"]').each(function(a, t) {
        var n = $(this).attr("data-async"),
            i = $(this);
        void 0 !== n && !1 !== n && ("true" == n || n) && i.attr("media", "all")
    })
});
</script>

Fügen Sie Ihrer Stylesheet-Referenz einfach Folgendes hinzu : media="none" data-async="true". Hier ist ein Beispiel:

<link rel="stylesheet" href="../path/script.js" media="none" data-async="true" />

Beispiel für jQuery:

<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" type="text/css" media="none" data-async="true" crossorigin="anonymous" /><noscript><link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" type="text/css" /></noscript>
Bradley
quelle
Ich denke, das asyncAttribut wird ignoriert, da das Skript-Tag nicht srcasynchron geladen werden muss ... oder ist es hier wirklich nützlich? Können Sie auch etwas näher erläutern, welchen Wert Sie als verwenden möchten nonce?
Philipp
0

Bitte aktualisieren Sie die Antwort, da alle oben genannten Punkte die Google Pagespeed-Erkenntnisse jetzt nicht beeindrucken.

Laut Google sollten Sie auf diese Weise das asynchrone Laden von CSS implementieren

 < noscript id="deferred-styles" >
        < link rel="stylesheet" type="text/css" href="small.css"/ >
    < /noscript >

<script>
  var loadDeferredStyles = function() {
    var addStylesNode = document.getElementById("deferred-styles");
    var replacement = document.createElement("div");
    replacement.innerHTML = addStylesNode.textContent;
    document.body.appendChild(replacement)
    addStylesNode.parentElement.removeChild(addStylesNode);
  };
  var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
      window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
  if (raf) raf(function() { window.setTimeout(loadDeferredStyles, 0); });
  else window.addEventListener('load', loadDeferredStyles);
</script>
Kaushik Gandhi
quelle
1
Wahrscheinlich ein falsches Positiv (PageSpeed-Fehler), wenn Sie den von mir erwähnten Preload-Keyword-Ansatz verwenden. github.com/filamentgroup/loadCSS/issues/53
jabacchetta
1
UPDATE: Google hat PageSpeed ​​Version 4 mit diesem Problem veraltet und anschließend heruntergefahren. Für diese Version wurde dieser asynchrone Code empfohlen. Obwohl ich in PageSpeed ​​5 nicht getestet habe : Angesichts der Beschreibung, wie sie jetzt testen, und ihrer Unterstützung für das "Preload" -Tag von "Link", ist Jabachettas Antwort jetzt wahrscheinlich eine bessere Antwort für Google.
ToolmakerSteve
1
@ToolmakerSteve Ja Diese Antwort muss häufig moderiert werden. Mit diesem Code erhalten Sie jedoch immer noch eine Seitengeschwindigkeit von 100.
Kaushik Gandhi
0

Ich habe versucht zu verwenden:

<link rel="preload stylesheet" href="mystyles.css" as="style">

Es funktioniert mit Geldstrafen, erhöht aber auch die kumulative Layoutverschiebung, da bei Verwendung von rel = "Preload" nur CSS heruntergeladen und nicht sofort angewendet wird.

Beispiel: Wenn das DOM-Laden einer Liste ul, li-Tags enthält, gibt es standardmäßig Aufzählungszeichen vor li-Tags. Dann hat CSS angewendet, dass ich diese Aufzählungszeichen für die Auflistung in benutzerdefinierte Stile entferne. Damit findet hier die kumulative Layoutverschiebung statt.

Gibt es dafür eine Lösung?

n2lose
quelle
0

Verwenden rel="preload"Sie diese Option , um es unabhängig herunterzuladen, und verwenden onload="this.rel='stylesheet'"Sie es dann , um es auf das Stylesheet as="style"anzuwenden ( ist erforderlich, um es auf das Stylesheet anzuwenden, da dies sonst onloadnicht funktioniert).

<link rel="preload" as="style" type="text/css" href="mystyles.css" onload="this.rel='stylesheet'">
Shammi Hans
quelle