Hier im Forum bekommt ihr bei euren fragen schnelle hilfe.Hier geht es rund um das Web SeitenProgrammieren.Alles rund ums Javascript,Html,Php,Css und Sql.Auf fast allen Fragen haben wir eine Antwort.
Der Soforthilfe-chat verspricht das ,was sein Name sagt. Hier sind Leute Online die sofort ihre hilfe anbieten.Seht in der OnlineListe nach und wenn einer Online ist werdet ihr auch antwort bekommen. Admine ,Moderatoren und Helfer sind unsere Spezialisten in Sachen Web Programierung

Sie sind hier : sebastian1012.bplaced.net/ homepage-neu / kreuz-und-quer / tutorials-info-neuigkeiten-css / index.php

Random Css Themen, Tutorials und co

24.09.2019 21:40:56

Einige Links

Heute bin ich auf eine interessante Webseite des O’Reilly-Verlags gestoßen, die sich mit Website Performance befasst. Der Verlag hat ja auch schon einige Bücher zum Thema herausgebracht. In diesem Beitrag möchte ich euch kurz einige Quellen nennen, die lesenswert sind.

Die Webseite, die ich gefunden habe, nennt sich treffend Website Optimization.
Zuerst ein Beitrag zu CSS Sprites, mit denen ich mich ja auch schon beschäftigt habe.
Außerdem ein weiterer Weg mehrere CSS-Dateien automatisch zusammen zu fassen, obwohl ich da eigentlich die Variante von Matthias besser finde (wenn man sie auf CSS überträgt).
Eine Zusamenfassung der Methoden bietet auch yensdesign.
Für die absoluten Optimierer gibt es einen Beitrag zur Verringerung des HTML-Codes, doch ich mahne zur Vorsicht. Wer das liest, sollte auch andere Quellen zu Rate ziehen, bevor er / sie die Änderungen durchführt, denn Tipps wie „Get rid of unnecessary closing tags </LI>, even </BODY>“ widersprechen natürlich jeglicher Validität. Manchmal wünsche ich mir schon, dass XHTML von den Browsern mit einem strengen XML-Parser verarbeitet würden, der einfach einen Fehler wirft, wenn die struktur kein XML ist … naja, nichtsdestotrotz sind in dem beitrag einige nützliche Ideen.

Oder hier noch was schönes zum Thema Parallelisierung / Verringerung von HTTP-Requests. Das hatte ich zwar auch schon beschrieben, aber ich freue mich immer wieder etwas über Performance-Themen zu lesen. Davon gibts leider viel zu wenig im Web, finde ich. Also wenn ihr da noch interessante Quellen kennt, würde ich mich über Kommentare freuen.

PS: Will keinen neuen Beitrag für aufmachen, aber habe hier noch 2 schöne Dinge zum Lesen:
1. Wie man einen Serverumzug mit möglichst wenig Problemen übersteht.
2. Und hier noch nen Screencast von Brenelz Web Solutions zum Thema transparente PNG-8-Bilder. PNG-8 ist wesentlich kleiner als PNG-24 und untersützt auch Transparenz und damit sind auch keine CSS- oder JS-Hacks nötig, um die Transparenz im IE6 anzuzeigen.

css

24.09.2019 21:40:56

CSS-Tuning mittels DATA-URI (base64)

Dieser Artikel soll als Ergänzung zum Artikel CSS-Sprites dienen, den Jan vor einem Jahr veröffentlicht hat. Ergebnis soll so sein: Internetwerbung (Quellcode der CSS-Datei)
Wie Jan bemerkt hat, ist die Verwendung von CSS-Sprites teilweise sehr tricky und liefert z.b. schlechte Ergebnisse wenn:

  • die kombinierten Bilder verschiedene Farbtiefen haben, weil das Ergebnisbild entweder die größte Farbtiefe aller Bilder hat und dadurch sehr groß wird, oder die kleinste Farbtiefe aller Bilder hat und dadurch eher unansehnlich wird. Zwischenwerte sind denkbar aber auch immer nur ein Kompromiss zwischen Qualität und Dateigröße
  • Angenommen man möchte 2 Bilder kombinieren: 1.) 1x1000px und 2.) 1000x1px, dann wird das Ergebnisbild entweder 1001x1000px oder 1000x1001px groß, d.h. was man durch Verringerung an HTTP-requests einspart, zahlt man durch zusätzliche Übertragungsdaten wieder drauf
  • das Problem mit Repeat bei sehr langen Seiten
  • beim Einfügen neuer Teilbilder muss ggf. das ganze „Sammelbild“ neu zusammengesetzt werden (inkl. Änderungen in der CSS-Datei).

Die Lösung heißt DATA-URI (base64)

Die Grundlagen dazu sind sehr gut in der englischen Wikipedia nachzulesen. Allerdings möchte ich euch einige (selbstentwickelte) Tuningmaßnahmen vorstellen. Zuerst muss gesagt werden, dass man mit dieser Methode sämtliche HTTP-Requests aus seiner CSS-Datei entfernen kann. Dadurch wird die CSS-Datei allerdings um die Summe aller verwendeten Bilder größer. Deshalb unbedingt Cache-Header verwenden!!! Da meine „Tuningmaßnahmen“ sehr serverlastig sind (Bildbearbeitung mittels PHP), empfehle ich dringend die Ergebnis-CSS-Datei zu cachen: Ich habe einen einfachen (aber wirkungsvollen) Cache implementiert.

So solls am Ende aussehen

Auf einer meiner Internetwerbung Seiten (die Seite ist egal, und dient nur Demonstationszwecken) kann man sich die CSS-Datei ansehen. Wenn man den Quelltext nach der Zeichenkette: „url(„ durchsucht, sieht man alle verwendeten Bilder als Teil der CSS-Datei und nicht mittels Link-Tag referenziert. Der Kommentar am Anfang ist nur informativ für mich und sagt mir die Zeichenzahl meiner CSS-Datei (=Größe).

Anleitung zum Umbau der CSS-Datei

Wer erstmal „nur“ testen möchte, kann gerne die Code-Schnipsel von Wikipedia verwenden. Ich habe diese weiterentwickelt und stelle sie euch hier exklusiv zur Verfügung.

  • CSS-Datei irgendwo sichern … man weiß ja nie ????
  • Falls noch nicht in der .htaccess vorhanden: Addtype application/x-httpd-php .css einfügen, damit die CSS-Datei durch den PHP-Interpreter läuft (alternativ kann auch die style.css in style.css.php umbenannt werden, aber dann müssen auch alle Referenzen im HTML-Code geändert werden)
  • Dem Root-Verzeichnis Schreibrechte 777 geben (aus Sicherheitsgründen nach Erzeugung der CSS-Datei die Schreibrechte wieder entfernen)
  • In der Index-Datei den Pfad zur CSS-Datei ändern in: style_neu.css
  • Folgenden PHP-Code an den Anfang der CSS-Datei einfügen: CSS-Code für base64-Codierung
  • Die alte CSS-Datei aufrufen, damit die neue CSS-Datei erstellt wird.
    Was Passiert? :
    Die bisherige CSS-Datei wird umgebaut und liefert die neue komprimierte CSS-Datei mit eingefügten Base64-Bildern. Die neue CSS-Datei wird unter dem Namen style_neu.css im Root-Verzeichnis gespeichert (ggf. kann man das anpassen (bedenkt: Schreibrechte 777 für den betroffenen Ordner setzen)). Die ganze Umwandlung besteht aus 3 Schritten:
    ob_start(‚compress‘);
    Der Ausgabepuffer wird aktiviert und komprimiert die bisherige CSS-Datei indem überflüssige Zeichen entfernt werden. Bemerkung: Falls jemand eine Methode (Code-Schnipsel) kennt, wie man die CSS-Datei noch weiter verkürzen kann (CSS-Shorthand-Erkennung, Zusammenfassung gleicher Parameter (wie in meinem CSS-Beispiel), u.ä.), bitte kurze Nachricht an mich (die Geschwindigkeit der Umwandlung ist egal, weil das Ergebnis gecached wird).
    function data_url
    Diese Funktion ist das eigentliche Herzstück. Sie wird für jedes Bild der CSS-Datei aufgefufen. Pflichtparameter sind: die Bild-Url ($file) und der MIME-Datentyp ($mime). Optionale Parameter sind die Seitenlängen des Bildes (damit das Bild, falls es nur verkleinert gebraucht wird, vor der Umwandlung in Base64 gestaucht werden kann) und die Qualität (0 <= X <= 100). Die ersten Zeilen legen fest, ob sich eine Bildbearbeitung lohnt. Ich lege fest, dass kleine Bilder (kleiner als 70 x 70px) prinzipiell Base64-Codiert werden sollen, weil bei diesen Bildern die HTTP-Requestzeit im Verhältnis zur eigentlichen Übertragungszeit sehr hoch ist. Dateien werden durch die Base64-Codierung ca. 1/3 größer. Dadurch kann es passieren, dass bei großen Bildern die Übertragungszeit stärker wächst, als die Zeiteinsparung durch Verringerung der HTTP-Requests. Und deshalb lasse ich diese Bilder lieber normal referenziert. Außerdem möchte ich Bilder codieren, die in der fertigen CSS-Datei (um mindestens 30%) kleiner sind als das Originalbild, weil die Einsparung durch die physische Verkleinerung des Bildes den zusätzlichen Traffic durch die Base64-Codierung wett macht.
    Ähnlich verhält es sich bei Bildern, die lediglich in geringer Qualität gebraucht werden (z.B. bei sehr kontrastarmen Bildern merkt man Qualitätsunterschiede kaum). Alle Bilder, die nicht ausgewählt wurden, werden wie bisher normal referenziert. Alle anderen (also die meisten der CSS-Datei) werden je nach Mime-Typ gestaucht. Die Verwendung des Ausgabepuffers in der Funktion ist ein Trick, damit man das Bild als String bekommt, den man dann in Base64 umwandeln kann. Die restlichen Funktionen sind reine Arbeitsfunktionen ohne (geistige) Leistung meinerseits.
    Schreiben-Funktion
    Wie man sich schon denken kann, übernimmt diese Datei den Schreibvorgang der fertig erzeugten CSS-Datei. Es wird noch der Header: Content-Type: text/css eingefügt und festgelegt, dass die Style_neu.css komprimiert an den Browser versendet wird. Das lohnt sich sehr, weil Base64-Code sehr stark komprimiert werden kann.
  • alle Stellen der CSS-Datei, an denen ein Bild mittels url(‚xxxxx.yyy‘) referenziert wird, werden ersetzt durch url([Base64-Code]), wobei Breite und Höhe unbedingt angegeben werden sollten, und den optionalen Parameter Qualität zwischen 1 und 100 (einfach mal ausprobieren, wie weit man die Qualität runterschrauben kann, bis man den Unterschied sieht).
  • kontrollieren, dass jedes externe Bild in genau einer CSS-Regel verwendet wird (notfalls Regeln neu sortieren), damit das selbe Bild nicht mehrfach in die CSS-Datei eingefügt wird. Beispiel: Bisher:
    .a{    height:18px;    margin:0 0 0 5px;    padding:0px;    background-image:url('a.jpg');    } .b{    height:20px;    margin:0 0 0 5px;    padding:0px;    background-image:url('a.jpg');    } .c{    height:22px;    margin:0 0 0 5px;    padding:0px;    background-image:url('a.jpg');    }

    Also 3 CSS-Regeln, die sich nur in verschiedenen Height-Werten unterscheiden.
    Müssen umgewandelt werden in:

    .a,.b,.c    {    margin:0 0 0 5px;    padding:0px;    background-image:url(<?=data_url('a.jpg','image/jpg',10,10)?>); /*angenommen breite und höhe sind 10px*/    } .a{    height:18px;    } .b{    height:20px;    } .c{    height:22px;    }

    Ergebnis: das Hintergrundbild ist jetzt nur noch in einer Regel und wird deshalb auch nur einmal in die CSS-Datei eingefügt. Kleiner Nebeneffekt: die redundanten margin- und padding-Werte wurden entfernt.

Benchmark

Ich habe auf meiner Seite beide Varianten mit YSlow getestet:
Vorher: 0,56s
Nachher: 0,79s (css nicht gecached (umwandlung on the fly))
Nachher: 0,25s (css gecached)

Fazit

Im ungecachetem Zustand wird die Zeiteinsparung durch die Verringerung der HTTP-Requests vollständig durch die Erstellungszeit der neuen CSS-Datei aufgebraucht. Ein Cache ist also unbedingt notwendig!

Nur nebenbei

Jan hatte ja schon erwähnt, dass die meisten Browser eine interne Beschränkung haben, was die Anzahl der gleichzeitigen HTTP-Requests angeht. Erwähnenswert ist, dass die meisten Betriebssysteme ebenfalls eine interne Beschränkung haben. D.h. es ist doppelt wichtig die Anzahl der Requests der eigenen Seite gering zu halten, weil es eben 2 Flaschenhälse gibt.

Nur Nebenbei II

Wer noch die letzten Prozente rausholen möchte, kann die gecachede Datei gleich gezipt speichern, damit beim Ausliefern die Zeit zum Zippen entfällt. Bei mir bringt das etwa 0,05s … (klingt wenig, entlastet den Server aber)

Ein kleines Quiz am Ende

Was wird hier gemacht?

echo '<link rel="icon" href="data:image/ico;base64,'.base64_encode(file_get_contents('images/favicon.ico')).'" />';
css

24.09.2019 21:40:58

Optimierungen von CSS und JavaScript on-the-fly

In meinem letzten Beitrag habe ich einige Möglichkeiten aufgezeigt, wie man HTML-, CSS und JavaScript-Code verkleinern kann ohne die Darstellung und Funktionalität zu beeinträchtigen. Wenn man jedoch keine Lust hat, immer nach einem Bearbeiten die Optimierungen wieder vorzunehmen, hab ich hier eine praktikablere Lösung. Außerdem wollen wir zusätzlich die Komprimierung der Daten einsetzen sowie das Client-side Caching einsetzen.
Das Ziel soll also eine Lösung sein, bei der wir mit unseren wohlstrukturierten Dateien weiterarbeiten können, aber trotzdem sollen möglichst wenig Daten vom Client geladen werden müssen.

Warum wollen wir eigentlich um jeden Preis die zu ladenden Daten so klein wie möglich halten? Es gibt 2 Gründe:

  • schnellerer Seitenaufbau: jedes Byte, was nicht geladen werden muss, beschleunigt den Seitenaufbau beim anfordernden besucher
  • geringere Kosten: oft ist das Trafficvolumen beim Webhosting oder Server begrenzt bzw. wird immer teurer je mehr Daten an den Client geschickt werden

Wenn wir es also schaffen, mit wenig Aufwand die Datenmenge zu verringern, können wir sowohl etas für unsere User als auch für unseren Geldbeutel tun.

Zuerst schauen wir uns CSS-Dateien an. Ich habe bereits bei Projekten mitgemacht, bei denen die CSS-Datei 40 kB groß war. Schönen Gruß an die 56k-Modem-User! Wir gehen hier natürlich davon aus, dass in der CSS-Datei nur wirklich genutzte Klassen und Definitionen enthalten sind – ansonsten wirkt dieser Tuningversuch lächerlich für das Projekt. Gut, wir nehmen und als Beispiel eine CSS-Datei mit einer Definition für das DIV-HTML-Element. Natürlich haben wir Multiformateigenschaften genutzt, um dadurch schon mal einige Bytes zu sparen, denn dabei geht die Übersicht auf keinen Fall verloren.

div {   font:bold 0.9em/12px Arial; /* fett groesse/zeilenabstand schriftart */   border:solid 1px red; /* typ breite farbe */   background:url(images/bild.jpg) top repeat-x; /* url position wiederholung */ }

Diese CSS-Datei kann nun nur noch durch 2 Dinge optimiert werden: Entfernung von Zeilenumbrüchen und Entfernen der Kommentare. Allerdings kann man mit der entstehenden 1-Zeilen-Datei später kaum noch arbeiten, deshalb wäre es doch toll, wenn diese Optimierungen zwar gemacht würden, wir uns aber nicht darum kümmern müssten.
Wir brauchen demzufolge ein Lösung, die on-the-fly die optimierte CSS-Datei erstellt und an den Client schickt. Um überhaupt an der Datei etwas ändern zu können, bevor sie geladen wird, brauchen wir erstmal PHP bzw. dessen Output Buffering. Dazu lassen wir unsere CSS-Datei(en) durch den PHP-Parser laufen. Das legt man über einen zusätzlichen Eintrag in der .htaccess fest (wenn diese Datei im root ihres Webprojekts noch nicht existiert, legen sie sie einfach an).
AddType application/x-httpd-php .css
Eine andere PHP über das Stylesheet schicken zu können, wäre die .css-Datei in .php umzubenennen, aber dann müssten alle Referenzierungen in der Anwendung umgeschrieben werden.

Was tun wir nun damit? Wir packen den PHP Output Buffer mit einer eigenen Callback-Funktion in die CSS-Datei. Die Callbackfunktion wird aufgerufen, nachdem die gesamte Dateiausgabe feststeht (der eigentliche CSS-Code geladen wurde), und erhält als Parameter genau diesen CSS-Code als String.

<?php header("Content-type: text/css"); ob_start("compress"); header ("content-type: text/javascript"); header ("cache-control: must-revalidate; max-age: 3600"); header ("expires: " . gmdate ("D, d M Y H:i:s", time() + 3600) . " GMT");   function compress($buffer) {   // remove comments   $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);   // remove tabs, newlines, etc.   $buffer = str_replace(array("\r\n", "\r", "\n", "\t"), '', $buffer);   //remove multiple spaces   $buffer = preg_replace('/\s\s+/', ' ', $buffer);   return $buffer; } ?> div {   font:bold 0.9em/12px Arial; /* fett groesse/zeilenabstand schriftart */   border:solid 1px res; /* typ breite farbe */   background:url(images/bild.jpg) top repeat-x; /* url position wiederholung */ } <?php ob_end_flush(); ?>

Die Funktion compress ist unsere Callback-Funktion. Wir bearbeiten den Buffer (den CSS-Code) durch das Entfernen von Kommentaren, Zeilenumbrüchen und Tabulatoren sowie mehrfachen Leerzeichen. Dadurch wird folgende CSS-Datei im Endeffekt wirklich an den Client geschickt:

div { font:bold 0.9em/12px Arial; border:solid 1px red; background:url(images/bild.jpg) top repeat-x; }

Durch diese recht trivialen Änderungen konnte die ursprüngliche Größe von 212 Bytes auf jetzt nur noch 103 Bytes verkleinert werden. Das sind über 50% weniger Daten! Und wenn man es mit der CSS-Datei vergleicht, bevor man Multiformateigenschaften genutzt hat (wenn man diese auflöst und alle Einzeleigenschaften aufschreibt kommt man auf 358 Bytes), beträgt die Speicherplatzeinsparung sogar über 70%!

Mit JavaScript-Dateien können wir ähnlich verfahren. Wir fügen die Endung .js zur .htaccess hinzu, damit sie vom PHP Parser verarbeitet wird. Bei JavaScript sind die gleichen Formatierungen möglich, nur müssen wir zusätzlich die einzeiligen Kommentare entfernen, da es sonst zu Problemen beim Entfernen von Zeilenumbrüchen kommen kann. Unsere Callback-Funktion sieht bei js-Dateien also so aus:

function function compress($buffer) {   // remove comments   $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);   $buffer = preg_replace('!//[^\n\r]*!', '', $buffer);   /*   Konstrukte wie    var variable = {     var1:"test",     var2:function() {       doSomething();     }   }   müssen nach der letzten schließenden Klammer ein Semikolon bekommen --> funktioniert nicht   */   //$buffer = preg_replace('/var ([^=]*) = \{(([^\}]*\})*)[\n\r]+/', "var ".'$1'." = {".'$2'.";", $buffer);   // remove tabs, spaces, newlines, etc. - funktioniert nicht, weil das vorhergehende nicht funktioniert   //$buffer = str_replace(array("\r", "\n", "\t"), "", $buffer);   $buffer = str_replace("\t", "", $buffer);   // multiple whitespaces   $buffer = preg_replace('/(\n)\n+/', '$1', $buffer);   $buffer = preg_replace('/(\n)\ +/', '$1', $buffer);   $buffer = preg_replace('/(\r)\r+/', '$1', $buffer);   $buffer = preg_replace('/(\r\n)(\r\n)+/', '$1', $buffer);   $buffer = preg_replace('/(\ )\ +/', '$1', $buffer);   return $buffer; }

In JavaScript gibt es komplexe Konstrukt (welche genau, steht im Kommentar im Quellcode), die ich versuche, durch ein Semikolon zu ergänzen. Leider funktioniert das nicht richtig. Aus diesem Grund habe ich auch nicht alle Zeilenumbrüche entfernt, denn sonst kommt es da zu Fehlern. Trotzdem bringt diese Funktion einiges an eingespartem Traffic.
Bei einem von mir geschriebenen Script zur Darstellung der Tooltips auf SucheBiete.com brachte diese Veränderung eine Einsparung von ca 20 % (Original: 3,24 kB, optimiert: 2,65 kB). Bei viel kommentierten Scripten wie beispielsweise Lightbox konnte ich sogar etwa 40 % einsparen (Original: 22,9 kB, optimiert: 13,8 kB).
Trotzdem muss ich sagen, dass es mit einigen JavaScripts Probleme gibt, beispielsweise mit der Bibliothek Prototype, da darin in Strings ‚/*‘ und ‚//‘ vorkommen. Man sollte also überprüfen, ob es nach dem Einbau JavaScript-Fehlermeldungen gibt.

Wenn diese On-the-fly-Optimierungen durchgeführt wurden, kann man die entstandenen Code dann noch als GZip senden, was die Größe des optimierten Codes auf ca ein Drittel zusammenpackt. Außerdem habe ich noch eine Cache-Control eingebaut, damit die Datei nicht jedes mal vom selben User erneut geladen wird.
Für CSS:

header("Content-type: text/css"); header ("cache-control: must-revalidate; max-age: 2592000"); header ("expires: " . gmdate ("D, d M Y H:i:s", time() + 2592000) . " GMT"); ob_start("compress"); function compress($buffer) {   // remove comments   $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);   // remove tabs, spaces, newlines, etc.   $buffer = str_replace(array("\r\n", "\r", "\n", "\t"), '', $buffer);   $buffer = preg_replace('/\s\s+/', ' ', $buffer);   if (stripos($_SERVER["HTTP_ACCEPT_ENCODING"],'x-gzip') !== false) {     header("Content-encoding:x-gzip");     $buffer = gzencode($buffer);   }   elseif (stripos($_SERVER["HTTP_ACCEPT_ENCODING"],'gzip') !== false) {     header("Content-encoding:gzip");     $buffer = gzencode($buffer);   }   elseif (stripos($_SERVER["HTTP_ACCEPT_ENCODING"],'deflate') !== false) {     header("Content-encoding:deflate");     $buffer = gzdeflate($buffer);   }   header('Content-Length: ' . strlen($buffer));   return $buffer; }

Entsprechend funktioniert es auch für JavaScript (außer eben mit den oben genannten Replaces). Wer eine js-Datei hat, die durch die angegebene Funktion nicht optimiert werden kann, weil dadurch Fehler entstehen, sollte zumindest gzippen. Wenn man aber nix mehr mit dem Buffer vorhat, reicht auch ob_start("ob_gzhandler");.

Durch diese kleinen Eingriffe lassen sich also durchaus ohne viel Aufwand (Vorsicht, Untertreibung) einige Bytes an Trafficvolumen einsparen.
An die On-the-fly-Optimierung von HTML-Code traue ich mich im Moment nicht so recht ran, weil das mittlerweile nicht mehr sauber ist. Erstens haben viele Seiten nicht valides HTML und zweitens erschweren Geschichten wie Conditional Comments und vorformatierte Bereiche (z.B. in Textareas und <pre>-Abschnitten) das Optimieren.

css

24.09.2019 21:40:57

Optimierung externer Client-Ressourcen durch Ant-Deploy-Prozess

Auf diesem Blog gibt es viele interessante Beiträge, wie man die Performance serverseitig verbessert.
Eine mindestens genauso gute Möglichkeit für eine Verbesserung der Performance ist, es dem Client-Rechner etwas leichter zu machen. Dieser Beitrag soll einen Überblick über die Möglichkeiten dazu geben.

Engpässe finden
Eine sehr hilfreiche Erweiterung ist die Firefox-Extension YSlow. Diese identifiziert Engpässe und gibt im Yahoo!-Developer-Network direkte Anleitungen und Hilfsmittel. Einige sollen hier näher erklärt werden

Der deploy-Prozess
Viele Punkte in YSlow, wie z.B: „Make fewer HTTP requests“, „Gzip components“ oder „MinifyJS“ können mit dem sogenannten deploy-Prozess erreicht werden. Ein deploy ist eine Methode, die aus den Entwicklungsdateien optimierte Versionen für den online-Einsatz erstellt, z.B. indem Dateien zusammengefasst oder komprimiert werden.

ANT
Ein wunderbares Tool, um den deploy-Prozess umzusetzen, ist ANT. ANT ist ein Java-Tool von Apache Foundation, das entweder als Konsolen-Tool oder aber – was ich wesentlich interessanter finde – als Eclipse-Plugin verwendet werden kann. Verwendet man PHPEclipse, ist ANT direkt vorinstalliert und kann über Window – Show View – ANT eingeblendet werden.

build.xml – Allgemein
ANT wird über eine xml-Datei gesteuert, die build.xml. Diese folgt bestimmten Formalien, damit ANT die Datei versteht. Um die Datei zu verwenden, klickt man in der ANT-View auf die Ameise mit dem grünen Plus daneben und wählt die build.xml-Datei aus. Danach ist der play-Button in der ANT-View aktiv und der deploy-Prozess kann theoretisch starten ????

build.xml – Aufbau
Die build.xml ist in sogenannte tasks untergliedert. Damit kann man seinen deploy-Prozess sauber strukturieren.
Hier mal eine beispielhafte build.xml-Datei:

<?xml version="1.0" encoding="UTF-8"?> <project name="dein_projektname" default="deploy" basedir=".">     <property name="tmp" location="Pfad/Zum/Temporaeren/DeployVerzeichnis" />     <target name="deploy">         <echo message="Dein deploy-Task"></echo>     </target> </project>

Mit einer property kann man eine Variable setzen, auf die dann später mit ${propertyName} zugegriffen werden kann.
In einem target kann man jetzt alle beliebigen ANT-Tasks ausführen.

Konkrete Umsetzung
Nun geht es an die konkrete Umsetzung der Aufgaben „Dateien zusammenfassen“, „Minifyen“ und „Gzip“.

Dateien zusammenfassen
Dieser Teil hat folgenden Vorteil: während der Entwicklungsphase können z.B. CSS-Dateien auseinander gehalten werden (layout.css, colors.css, forms.css), in der Online-Version muss aber nur eine Datei (general.css) vom Server geladen werden. Das bedeutet weniger HTTP Requests und weniger HTML-Code, um die einzelnen CSS-Dateien einzubinden. Um eine zusammengefasste Datei zu erstellen, wird der concat-Befehl verwendet:

<concat destfile="${tmp}/general.css" force="no" fixlastline="true">     <filelist dir="pfad/zu/deinen/cssdateien">         <file name="layout.css" />         <file name="colors.css" />         <file name="forms.css" />     </filelist> </concat>

Darin gebt ihr die Zieldatei an und welche Dateien zusammengefasst werden sollen. Damit es kein Durcheinander in den Dateien gibt, die Datei am Besten in ein temporäres Verzeichnis (${tmp}) legen.

Minify
Minify entfernt Leerzeichen und Zeilenumbrüche und ersetzt
function meinLangerFunktionsname()
durch
function A()
Das bringt eine Ersparnis von bis zu 70% in der Dateigröße! Und keine Sorge, dass hier was durcheinander kommt ???? In aktuellen Projekten von mir werden über 100 JavaScript-Dateien damit gehandelt und es funktioniert 1a.
Um ein Minify durchzuführen gibt es verschiedene Tools, die man mit ANT ausführen kann. Ich verwende das von Yahoo. Dafür müsst ihr yuicompressor und YUIAnt runterladen. Anschließend folgenden Code außerhalb eines tasks in eure build.xml einfügen:

<taskdef name="yuicompress" classname="com.yahoo.platform.yui.compressor.YUICompressTask">    <classpath>      <pathelement path="pfad/zu/den/tools/yuicompressor-2.3.5.jar" />      <pathelement path="pfad/zu/den/tools/YUIAnt.jar" />    </classpath>  </taskdef>

So, jetzt haben wir die technischen Voraussetzungen, um den minify-Prozess durchzuführen. Das geht so:

<yuicompress linebreak="300" warn="false" munge="yes" preserveallsemicolons="true" outputfolder="${tmp}">   <fileset dir="${tmp}/" >     <include name="**/*.js" />     <include name="**/*.css" />   </fileset> </yuicompress>

Zwischenstand
Im temporären Verzeichnis liegen jetzt die zusammengefassen und minifyten JavaScript- und CSS-Dateien. Sind schon schön klein geworden, oder :-)? Um hier noch mehr an der Größe zu tun, können diese Dateien noch gzip-komprimiert werden.

Gzip-Komprimierung
Hierfür sind keine besonderen Tools notwendig, es reicht eine Zeile:

<gzip src="${tmp}/general.css" destfile="pfad/zu/deinem/htdocs/verzeichnis/general.css"/>

Der Gzip-Vorgang kann leider nicht über ein fileset gemacht werden, sondern jede Datei braucht eine eigene Zeile…

Ergebnis
Die Dateien sind jetzt perfekt für den Online-Einsatz vorbereitet und ihr müsst trotzdem kein bisschen auf Übersichtlichkeit oder andere Strukturierung während der Entwicklung verzichten.
Die fertige build.xml sieht so aus:

<?xml version="1.0" encoding="UTF-8"?> <project name="dein_projektname" default="deploy" basedir=".">     <!-- Variablen festlegen -->   <property name="tmp" location="Pfad/Zum/Temporaeren/DeployVerzeichnis" />     <!-- Definition des Minify-Tasks -->   <taskdef name="yuicompress" classname="com.yahoo.platform.yui.compressor.YUICompressTask">     <classpath>       <pathelement path="pfad/zu/den/tools/yuicompressor-2.3.5.jar" />       <pathelement path="pfad/zu/den/tools/YUIAnt.jar" />     </classpath>   </taskdef>     <!-- Der deploy-Task -->   <target name="deploy">     <echo message="Dein deploy-Task"></echo>       <!-- Die Dateien zu einer zusammenfassen -->     <concat destfile="${tmp}/general.css" force="no" fixlastline="true">       <filelist dir="pfad/zu/deinen/cssdateien">         <file name="layout.css" />         <file name="colors.css" />         <file name="forms.css" />       </filelist>     </concat>       <!-- Die Dateien minifyen -->     <yuicompress linebreak="300" warn="false" munge="yes" preserveallsemicolons="true" outputfolder="${tmp}">       <fileset dir="${tmp}/" >         <include name="**/*.js" />         <include name="**/*.css" />       </fileset>     </yuicompress>       <!-- Die Dateien gzipen -->     <gzip src="${tmp}/general.css" destfile="pfad/zu/deinem/htdocs/verzeichnis/general.css"/>   </target> </project>

Jetzt in der ANT-View in Eclipse play drücken ????
Wenn ihr es ausprobieren und nicht Stück für Stück aus diesem Artikel kopieren möchtet, könnt ihr die fertige build.xml auch herunterladen.

Ich hoffe, diese kurze Einführung in die Arbeit mit einem deploy-Prozess und ANT hat euch weitergeholfen.

Christian

css

24.09.2019 21:40:57

CSS Sprites – Einsparung an HTTP-Requests durch Kombination von Hintergrund-Bildern

Wie sich ja gewünscht wurde, möchte ich von nun an auch etwas mehr über die Performance von Client-Systemen in Bezug auf Webanwendungen schreiben. Genauer: Wie müssen Webseiten ausgeliefert werden, damit Sie möglichst schnell im Browser des Besuchers dargestellt werden können?
In diesem Beitrag soll es dabei um die CSS Sprites bzw. Image Sprites gehen. Die Yahoo-Präsentation hat ja bereits darauf hingewiesen und hier soll nun erklärt werden, wie es funktioniert.

Problemstellung
Ein Problem, weshalb Seiten oft lange Ladezeiten haben, ist, dass recht viele HTTP-Requests gemacht werden müssen. Da HTTP ein zustandsloses Protokoll ist, muss für jedes Bild, jede JS-Datei und allgemain jede externe Ressource eine neue HTTP-Verbindung zwischen Browser und Server eröffnet werden. Das wäre ja noch nicht problematisch (lediglich umständlich). Das Problem ist aber, dass je nach Browser nur eine bestimmte Anzahl an parallelen HTTP-Requests ausgeführt werden können (oft 2-4). Im Firefox kann diese Einstellung über network.http.max-persistent-connections-per-server auf der about:config-Seite verändert werden.
Dadurch entsteht ein Treppen-Diagramm, das die Gesamtladezeit verdeutlicht: Treppeneffekt beim Laden mehrerer externer Ressourcen
Es wird deutlich, dass einige Beschleunigung des Ladens erreicht werden kann, wenn entweder die Anzahl paralleler Requests erhöht wird oder die Anzahl an Requests verringert wird. Ersteres kann beispielsweise durch unterschiedliche Subdomains gemacht werden (eine für Bilder, eine für JS usw.). Genaueres dazu findet sich beim Beitrag, wenn man auf den Link des Diagramms klickt.
Wir wollen uns jetzt aber mal mit dem anderen Punkt beschäftigen: der Verringerung der HTTP-Requests.

HTTP-Requests verringern könnte man auf 2 Arten: Mehrere Komponenten innerhalb einer Datei konsolidieren (ich hasse dieses Wort, seitdem es in jeder IT-Zeitung steht) oder die Komponenten inline in das HTML-Dokument einbinden. Letzteres geht beispielsweise gut bei CSS (wird z.B. auf Yahoo gemacht) aber auch bei Bildern (aber dann wird der Quellcode richtig hässlich).
Hier soll es um die Konsolidierung mehrerer Komponenten gehen, genauer um das Verringern von Anfragen für Hintergrundbilder.

Jedes mit CSS über url() referenzierte Hintergrundbild benötigt natürlich auch einen HTTP-Request. Aber habt ihr euch mal alte Spiele angesehen (bei aktuellen weiß ichs nicht, dafür hab ich leider kaum noch Zeit)? Dort sind meistens verschiedene GUI-Elemente in einer einzigen Bilddatei zusammengefügt. Hinterher schneidet sich dann das Programm den gewünschten Teil raus. Das spart Speicherplatz und Ladezeit.

Übertragen auf die Webentwicklung ist es ganz ähnlich: Mehrere Hintergrund-Bilder können in eine Grafik-Datei gepackt werden und später trotzdem an der richtigen Position angezeigt werden.
Der erste Schritt dafür ist das Zusammenpacken in eine Datei. Das geht ganz gut mit einem CSS-Sprite-Generator. Dabei sollte allerdings dringend darauf geachtet werden, dass man entweder nur Bilder nimmt, die später horizontal wiederholt werden (repeat-x) oder nur Bilder, die vertikal wiederholt werden (repeat-y) (bei mir traf ersteres dazu, deshalb kann ich die Tauglichkeit des verlinkten Generators für Letzteres nicht einschätzen). Zu den Gründen unten mehr.
Jedenfalls spuckt der Generator letztlich eine Bilddatei aus, in der alle eure Hintergründe enthalten sind. Dazu gibts noch einen CSS-Code.

Allein mit den Anweisungen dort beim Generator habe ich es allerdings nicht hinbekommen, die Sprites zum Laufen zu bekommen, sondern mir war noch dieser Beitrag behilflich. Zuerst muss die Sprite-Grafikdatei nämlich einmal eingebunden werden. Und zwar am besten für alle CSS Regeln, bei denen eines der im Sprite enthaltenen Bilder als Hintergrundbild genutzt wird. (Beispiel siehe unten)

Anschließend kann man sich um das Ersetzen der alten Hintergrundregeln kümmern, denn die werden nun nicht mehr benötigt. Je nachdem, welche CSS-Regeln obiger Generator ausspuckt, ersetzt ihr background-image nun nur noch durch background-position (also inklusive den vom Generator ausgepuckten Werten). Dadurch wird das Sprite an die für das bestimmte Element korrekte Position verschoben.

Nun aber zum repeat. Wenn ihr bisher die Multiformat-Eigenschaft background benutzt habt, müsst ihr das jetzt aufdröseln, denn es wird ja nur noch background-position und background-repeat benötigt. Jedenfalls werdet ihr eventuell schnell merken, dass wenn ihr repeat-x verwendet, es kein hübsches Hintergrundbild wie früher gibt. Der Grund dafür sind unterschiedlich breite Hintergrundbilder. Dadurch entstehen mitunter neben dem Bild weiße (oder transparente; je nachdem, was man einstellt) Ränder. Für ein repeat-x werden aber durchgängige Bilder benötigt.
Deshalb gibt es 2 Wege dieses Problem zu beheben: Entweder alle Bilder nachträglich auf gleiche Breite ziehen. Oder (von mir präferiert) einfach nur den ersten Pixel in der Breite des Sprite-Bildes verwenden (bzw. gleich nur 1px breite Bilder dem Sprite-Generator geben). Kann man ganz einfach per Irfan View oder auch irgendeinem anderen Grafikprogramm auswählen, freistellen / kopieren und entsprechend abspeichern. Es ist sowieso nur ein 1px breites Bild erforderlich, da der Rest ja per repeat-x generiert wird.

Und jetzt kommt noch das zweite Problem, auf das ich gestoßen bin: Ich habe einen Seiten-Hintergrund, der 500px hoch ist (Verlauf). Wenn die Seite länger ist, wird einfach die angegebene Hintergrundfarbe angezeigt. Wenn nun aber unterhalb dieses Bildes im Sprite noch ein völlig anderer Hintergrund kommt, weiß CSS natürlich nicht, wo es das Bild beenden soll (insbesondere da man per CSS zwar das Hintergrundbild verschieben nicht aber einen bestimmten Bereich ausschneiden kann). Entsprechend wird dann einfach der darunterliegende Hintergrund noch mit angezeigt. Entweder man wählt zur Behebung dieses Problems sehr große vertikale Abstände zwischen den einzelnen Hintergründen (diese Lösung ist allerdings nicht sehr flexibel, denn eventuell wird in der Zukunft eine noch längere Seite erstellt, wo der Abstand dann nicht mehr ausreicht) oder man wählt für das Sprite nur Hintergrundbilder von Elementen, deren Höhe feststeht (per CSS-Attribut height; teilweise auch bei Inline-Elementen, jedoch muss da eventuell auf die Schriftgröße geachtet werden – ist diese nämlich relativ angegeben, ist auch die Höhe des Elements variabel).

Nun noch ein kleines Beispiel zur Verdeutlichung:
Alte Regeln:

#header {background: url(bild1.jpg) top left repeat-x; height:80px;} ul.menu li {background: url(bild2.jpg) top left repeat-x; height:15px;}

bild1.jpg und bild2.jpg sind jeweils 1px breit. Durch den Sprite-Generator jagen, Sprite-Datei runterladen bzw. auf Webserver hochladen.

Sprite-Bild einmalig einbinden für alle Elemente, die einen im Sprite enthaltenen Hintergrund haben:

#header, ul.menu li {background-image:url(bg_sprite.png);}

Mit Hilfe der im Generator angegebenen Regeln die alten Regeln ersetzen:
Generator spuckt zum Beispiel aus:

.sprite-bild1 { background-position: 0 -30px; }  .sprite-bild2 { background-position: 0 -110px; }

Einbau in vorhandenes CSS:

#header {background-position: 0 -30px; background-repeat: repeat-x;} ul.menu li {background-position: 0 -110px; background-repeat: repeat-x;}

Und das wars. Mit 2 Bildern macht das noch nicht so viel Sinn, aber ich denke das reicht zum Verdeutlichen.

Falls ihr noch Fragen habt zu diesem Thema, freue ich mich über Kommentare. Euren Erfolg durch diese Maßnahme prüfen könnt ihr übrigens mit Firebug (Tab Net) sowie YSlow (Tab Performance).

css