Um den HTML-Code schlank zu halten, doppelten Code zu vermeiden und Browser-Caching optimal einsetzen zu können, lagern viele Entwickler JavaScript- und CSS-Code in eigene Dateien aus und referenzieren diese Dateien anschließend im HTML-Code mit dem <script>- bzw. <link>-Tag. Doch sollte einiges beachtet werden.
Zuerst ist zu sagen, dass auf CSS-Dateien stets im <head> der Seite referenziert werden sollte und auf JavaScript am Ende des Bodys. Das ist deshalb gut, weil der Browser dann sofort alle CSS-Regeln hat und sofort mit der Formatierung der HTML-Elemente beginnen kann. Ansonsten wartet der Browser mit dem Rendering der Seite bis alle CSS-Dateien geladen sind.
JavaScript-Dateien sollten aus dem Grund direkt vor </body> eingefügt werden, da mit JavaScript HTML-Elemente erzeugt werden können, z.B. durch document.write() oder document.createElement(). Dadurch wird der HTML-Baum verändert. Deshalb muss der Browser mit dem Rendern des folgenden HTML-Codes warten bis die JavaScript-Datei geladen ist (denn der Browser weiß ja vorher nicht, was in der JS-Datei gemacht wird).
Mehr dazu, warum CSS im Head eingebunden werden sollte, gibt es bei Google Page Speed und im Yahoo Developer Network.
Nun kommt es aber manchmal vor, dass man noch einzelne kleine Code-Anweisungen nicht auslagern kann, beispielsweise wenn per PHP noch eine Variable eingefügt werden muss. Man hat dabei zwei Möglichkeiten:
- Dynamische CSS- bzw. JS-Datei per PHP-Script erstellen und Variable als GET-Parameter übergeben
- CSS- bzw. JS-Code mit dem Parameter direkt in den HTML-Code unterbringen
zu 1.: Diese Variante ist sehr schlecht, da mit der Änderung des Parameters sich der Dateiname der Ressource ändert. Dadurch muss die gesamte Datei erneut geladen werden, denn der Browser kann nicht auf die Datei aus dem Browser-Cache zugreifen.
zu 2.: erstmal noch kurz, was genau mit parametrisierten CSS- und JS-Anweisungen gemeint ist:
<style type="text/css"> .klasse { width: <?php echo $breite; ?> } </style> <link rel="stylesheet" href="restliches_CSS.css" type="text/css" /> <script type="text/javascript"> var elemente = "<?php implode(",",$elementeArray); ?>"; </script> <script src="restliches-Javascript.js" type="text/javascript"></script> |
Diese Variante ist besser, da der größte Teil der Ressource aus dem Browser-Cache geladen werden kann. Aber es gilt folgendes zu beachten:
Wie oben gesagt, beginnt der Browser erst mit dem Rendering, sobald er alle CSS-Dateien und -regeln geladen hat. Deshalb sollten die parametrisierten CSS-Regeln, die im HTML-Code stehen möglichst auch im <head> stehen. Es ist aber zu beachten, dass JavaScript-Code zwischen 2 externen Ressourcen die Parallelisierung verhindert. Deshalb sollten stets alle externen JS-Dateien direkt hintereinander eingebunden werden. Erfolgt zwischen den einzelnen Referenzierungen zu CSS-Dateien oder JS-Dateien ein JS-Befehl, kann der Download nicht parallel erfolgen.
Beispiel (ganz schlecht):
<head> <link rel="stylesheet" type="text/css" href="stylesheet1.css" /> <script type="text/javascript" src="scriptfile1.js" /> <script type="text/javascript" src="scriptfile2.js" /> <link rel="stylesheet" type="text/css" href="stylesheet2.css" /> <link rel="stylesheet" type="text/css" href="stylesheet3.css" /> </head> |
Hier wird der Download der Dateien stylesheet2.css und stylesheet3.css blockiert, weil die JS-Dateien dazwischen den HTML-Baum verändern könnten.
Beispiel (auch schlecht):
<head> <link rel="stylesheet" type="text/css" href="stylesheet1.css" /> <script type="text/javascript"> document.write("Hello world!"); </script> <link rel="stylesheet" type="text/css" href="stylesheet2.css" /> <link rel="stylesheet" type="text/css" href="stylesheet3.css" /> </head> |
Zuerst wird die Ausführung des Inline-Style-Befehls durch stylesheet1.css verzögert. Anschließend verhindert die Inline-Anweisung wiederum, dass die Stylesheets parallel heruntergeladen werden können.
Beispiel (gut):
<head> <link rel="stylesheet" type="text/css" href="stylesheet1.css" /> <link rel="stylesheet" type="text/css" href="stylesheet2.css" /> <link rel="stylesheet" type="text/css" href="stylesheet3.css" /> <script type="text/javascript"> document.write("Hello world!"); </script> </head> |
Zuerst alle externen Ressourcen einbinden. Alle werden parallel heruntergeladen. Anschließend das Inline-Script. Natürlich sollte das JavaScript möglichst weit unten in den Body geschrieben werden, da es genauso das Laden von Bildern verzögert.
Alle Beispiele stammen von hier.
Folgende Tipps kann ich demzufolge geben:
- alle CSS-Datei-Referenzierungen per <link>-tag in den <head> direkt hintereinander schreiben
- alle <script>-Tags direkt vor </body> (wenn möglich)
- möglichst keine JS-Anweisungen (inline oder extern) zwischen CSS-Referenzierungen
- keine JS-Inline-Anweisungen zwischen mehreren Referenzierungen auf JS-Dateien
Interessant in diesem Zusammenhang ist auch der Beitrag von Rakesh Pai namens Download JavaScript Files in Parallel. Er geht dabei auf das HTML-Attribut defer ein, das schon lange im Internet Explorer und seit Version 3.1 auch im Firefox implementiert ist. Damit umgeht man die Blockierung anderer Ressourcen durch JavaScript, da das defer einfach dem Browser mitteilt, dass das Script nicht sofort geladen werden muss, sondern erst, wenn der gesamte Body geladen ist. Dadurch brauchen dann andere Ressourcen nämlich auch nicht blockiert zu werden. Dadurch bräuchten die JS-Referenzierungen dann auch nicht mehr zwingend ganz am Ende des Bodys stehen.
Externes JavaScript immer erst am Ende der Seite? Interesant, bisher hatte ich es immer im <head>. Werde dazu mal selbst einen Testlauf starten.
Dazu ist sicher die Beiträge Optimize the order of styles and scripts don’t use @import interessant.
Danke für den guten Beitrag.
Ich werde wie Daniel (#1) in den nächsten Tagen mal meine Tests starten.
Toller Artikel! Danke!
Hallo,
zugegeben war das hier komplett alter Hut für mich aber ist ja nicht tragisch.
Wenn man sich für den Firefox das Add-On Firebug installiert, gibts noch ein paar Addon-Addons. Unter anderem das hier mal irgendwann vorgestellte YSlow, aber auch „Page Speed“ von Google:
http://code.google.com/intl/de-DE/speed/page-speed/download.html
Mithilfe von FireBug + YSlow + PageSpeed habe ich zB bei meiner Page so ziemlich alles verbessert was ohne großen Arbeitsaufwand realisierbar war. Performancegewinn von gefühlten 40-50%.
Erst lesen dann schreiben^^ Sorry. Hatte den Text nur überflogen. Steht ja bereits mitten drin.
Sorry, I don’t speak German, so my comment is in English.
Actually, the defer attribute is not required in IE for the script download to happen in parallel. I know my original code had it, but it didn’t make a difference if I removed it, so I removed it. 🙂
I’m glad you liked the script. Just be sure to get the latest version from my blog if you need to use it.
Kenn diese Tricks auch schon etwas länger dank Google Page Speed, aber finde es hier einmal nett zusammengefasst 🙂
das ist ja ein blog hier, da wird man doch direkt rausgelöscht wenns den star programmierern nicht passt.
als ob man hier auch nur irgendetwas selber rausgefunden hätte…
@schlauberger: Was wurde denn gelöscht? Ich habe nix gelöscht. Eventuell hat der Spamfilter zugeschlagen, aber da habe ich jetzt auf Anhieb auch nix gefunden.
Hi,
Mehrere Javascript Dateien zu einer zusammen zu fassen bringt einiges, aber wenn man das Javascript noch minified kann der gesamte Code auch komprimiert werden.
http://code.google.com/p/jsmin-php/
In bezug auf die Generierung würde ich empfehlen, die Dateien zu cachen, denn der Komprimierungsprozess muss ja nicht ständig neu erfolgen.
Nun, das mit dem JavaScript am Ende des Body kommt aber auch auf das Script drauf an. Ein FrameBrecher funktioniert dort nämlich nicht. Der zerschießt dann auch die Frames von Adsense.
Nicht alle Javascripte können vor dem positioniert werden. z.B. JQuery und co. laufen den nicht und die sind nun mal sehr groß weshalb es sich dort lohnen würde.