Kürzlich stand ich wieder einmal vor einem interessanten Problem, welches es zu lösen galt. Eine bestimmte Aktion sollte ausgeführt werden, wenn ein Element (bspw. durch Klicken) sichtbar gemacht wird. In diesem Fall sollte eine asynchrone Anforderung (AJAX) ausgeführt werden. Weil ich aber ein jQuery-Accordion eingesetzt habe, hatte ich keinen direkten Zugriff auf die show-Methode (mal abgesehen vom Umschreiben selbiger). Daher musste ein Weg gefunden werden, eine Aktion auszulösen, sobald sich die Sichtbarkeit des Elements änderte.
Nach ein wenig rumsuchen habe ich schließlich die passenden Events gefunden: DOMAttrModified für Firefox und Opera und onpropertychange für den Internet Explorer (für Chrome und Safari gibt es leider keine einfache Lösung). Dazu die beiden Definitionen:
Occurs after Attr.value has been modified and after an Attr node has been added to or removed from an Element. Document Object Model (DOM) Level 3 Events Specification
Fires when a property changes on the object. onpropertychange Event
Beide Events können in jQuery für ein Element zugleich an einen Eventhandler gebunden werden (man beachte, dass das Event für den IE hier nur propertychange heißt):
$('#elem').bind('DOMAttrModified propertychange', myfunc)
Beim Accordion ändern sich aber ständig die Attribute, wenn es auf- oder zuklappt aufgrund der Animation. Daher wollte ich es nur einmal ausführen lassen. Dies geschieht über die jQuery-Methode one().
$('#elem').one('DOMAttrModified propertychange', myfunc)
In der Funktion myfunc(e) hat man dann, über den standardmäßig übergebenen ersten Parameter e, Zugriff auf das Event-Objekt. Im Internet Explorer geschieht dies über das globale window.event-Objekt.
Im Event-Objekt kann man schließlich leicht überprüfen, ob das Objekt gerade eingeblendet wurde. Dazu stellt das Event-Objekt die Eigenschaft newValue zur Verfügung, welche man nur auf den Wert display: block; überprüfen muss (wird von show() standardmäßig gesetzt). prevValue gibt die vorherigen Attribute (evtl. mehrere!) aus.
Im Internet Explorer sollte man das globale window.event.propertyName überprüfen und gleichzeitig checken, wie die neuen Attribute sind. Dazu prüft man die Eigenschaft window.event.srcElement.style.display auf den Wert block.
Zusammenfassend sieht der Code für die (einmalige) Überwachung der Zustandsänderung und die auszuführende Aktion so aus:
$('#elem').one('DOMAttrModified propertychange', function(e) {
if((e.attrName == 'style' && e.newValue == 'display: block;') || (window.event.propertyName == 'style.display' && window.event.srcElement.style.display == 'block')) {
alert('Ich bin sichtbar geworden');
// weitere Aktionen hier einfügen
}
});
Heute werde ich wieder einmal eine nützliche PHP-Funktion vorstellen. Genauer gesagt handelt es sich um eine Klasse, die CSS und JavaScript komprimieren kann. Bei diesem Minification (oder minify) genannten Prozess, werden unnötige Kommentare, Leerzeichen, Tabulatoren und Zeilenumbrüche entfernt, wodurch die Datei kleiner wird und so schneller an den Benutzer übertragen werden kann. Zusätzlich kann in der Klasse der „bereinigte“ Quellcode auch noch vor der Übertragung mit gzip oder Deflate komprimiert werden, damit er noch schneller übertragen werden kann.
<?php
class minifier {
public function minify_CSS($str, $zip = FALSE) {
$str = str_replace(array("\r", "\n", "\t"), '', $str);
$str = preg_replace('#/\*(.*)\*/#U', '', $str);
header('Content-Type: text/css; charset=UTF-8');
header('Cache-Control: public, max-age=1209600');
if($zip === TRUE)
$str = $this->zip($str);
echo $str;
}
public function minify_JS($str, $zip = FALSE) {
$str = preg_replace('#//.*#', '', $str);
$str = str_replace(array("\r", "\n", "\t"), '', $str);
$str = preg_replace('#/\*(.*)\*/#U', '', $str);
header('Content-Type: text/javascript; charset=UTF-8');
header('Cache-Control: public, max-age=1209600');
if($zip === TRUE)
$str = $this->zip($str);
echo $str;
}
protected function zip($str) {
if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) === TRUE) {
if(stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') !== FALSE) {
header('Content-Encoding: deflate');
$str = gzdeflate($str, 9);
} elseif(stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE) {
header('Content-Encoding: gzip');
$str = gzencode($str, 9);
}
}
return $str;
}
}
?>
Die Klasse kann dann in einer beliebigen Datei so aufgerufen werden:
<?php
require_once('minifier.class.php');
$min = new minifier();
$min->minify_JS('[JavaScript-Quellcode]', TRUE);
$min->minify_CSS('[CSS-Quellcode]', TRUE);
?>
Im Gegensatz zu vielen anderen Minifiern habe ich versucht die Optimierungen „leichtgewichtig“ zu gestalten, also einen Kompromiss aus Bandbreiteneinsparung und Ressourcenschonung zu finden. Viele andere Minifier nehmen nämlich noch mehr Optimierungen vor (Variablenumbenennung, komplizierte RegEx-Konstrukte), die viel Rechenzeit benötigen und daher nur bedingt für die On-the-fly-Erstellung von komprimiertem Code geeignet sind. Sicherlich lassen sich damit die Dateigrößen teils erheblich weiter reduzieren aber auf Kosten der serverseitigen Performance.
Auf blogeum wird die Klasse in einer erweiterten Form auch eingesetzt, um CSS und JS vor der Übertragung zu verkleinern und die Übertragungszeiten zu vermindern.
Wie immer steht der Code unter einer Creative Commons-Lizenz.
In einem Gastbeitrag bei Peter Kröner informiert Christian Schaefer, wie man die Ladezeiten einer Website ohne großen Aufwand drücken kann, um die Besucher nicht durch lange Ladezeiten zu vergraulen und einen guten Eindruck zu hinterlassen.
Schließlich zählt die Ladezeit mit zu den Erfolgsfaktoren einer Website und wird zukünftig auch in das Ranking bei den Google-Suchergebnissen eingehen.
Am Ende des Artikels stellt er noch seine PHP5-Bibliothek CSS-JS-Booster vor, die einem die Arbeit bei einigen der vorgestellten Tipps abnimmt und automatisch kombiniert.
Alles in allem ein lesenswerter Artikel und einige sinnvolle Tipps, die einfach umzusetzen sind!
Jedem Webworker ist sicher schon einmal folgendes Problem untergekommen:

Da ich immer wieder eine recht rustikale Lösung des Problems sehe, möchte ich einmal auf eine viel trickreichere und schönere hinweisen.
Das Problem
Zwei Boxen (DIV) sollen nebeneinander innerhalb einer weiteren Box positioniert und darum einen Rahmen oder eine Hintergrundfarbe gesetzt werden. Das CSS-Box-Model (bzw. dessen Auslegung) verhindert nun aber, dass die umgebende Box so weit erweitert wird, sodass beide DIVs umfasst werden. Hierzu sei folgender HTML-Quelltext gegeben:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
<title>Textumfluss-Problem</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style type="text/css">
body {background-color: #FFF; font: 62.5%/1.8em Arial, Helvetica, Sans-Serif;}
#wrap {border: #F08080 5px solid; margin: 0 auto; padding: 5px; width: 500px;}
#wrap p {font-size: 1.2em; margin: 5px; width: 48%;}
#wrap p#one {background: #B0C4DE; float: left;}
#wrap p#two {background: #B0C4DE; float: right;}
</style>
</head>
<body>
<div id="wrap">
<p id="one">Er hörte leise Schritte hinter sich. Das bedeutete nichts Gutes. Wer würde ihm schon folgen, spät in der Nacht und dazu noch in dieser engen Gasse mitten im übel beleumundeten Hafenviertel? Gerade jetzt, wo er das Ding seines Lebens gedreht hatte und mit der Beute verschwinden wollte! Hatte einer seiner zahllosen Kollegen dieselbe Idee gehabt, ihn beobachtet und abgewartet, um ihn nun um die Früchte seiner Arbeit zu erleichtern? Oder gehörten die Schritte hinter ihm zu einem der unzähligen Gesetzeshüter dieser Stadt, und die stählerne Acht um seine Handgelenke würde gleich zuschnappen?</p>
<p id="two">Er konnte die Aufforderung stehen zu bleiben schon hören. Gehetzt sah er sich um. Plötzlich erblickte er den schmalen Durchgang. Blitzartig drehte er sich nach rechts und verschwand zwischen den beiden Gebäuden. Beinahe wäre er dabei über den umgestürzten Mülleimer gefallen, der mitten im Weg lag. Er versuchte, sich in der Dunkelheit seinen Weg zu ertasten und erstarrte: Anscheinend gab es keinen anderen Ausweg aus diesem kleinen Hof als den Durchgang, durch den er gekommen war. Die Schritte wurden lauter und lauter, er sah eine dunkle Gestalt um die Ecke biegen. Fieberhaft irrten seine Augen durch die nächtliche Dunkelheit und suchten einen Ausweg.</p>
</div>
</body>
</html>
Typischerweise würde man dieses Problem lösen, indem man der äußeren Box #wrap auch ein float-Attribut mitgibt und so einen Textumfluss erzwingt.
Nun muss jedoch der Umfluss direkt nach der Box wieder abgebrochen werden, weil sonst die nachfolgenden Elemente die Box umfließen würden.
<br style="clear: both;" /> und Konsorten werden hierfür typischerweise hergenommen. Dummerweise blähen sie den Quelltext unnötig auf und erschweren die Wartbarkeit. Ein unschöner Notbehelf also.
Ein neuer Ansatz
Wie löst man also heutzutage dieses Problem? Der Schlüssel zur Lösung liegt im CSS-Attribut overflow und dessen Eigenschaft hidden. Danke an Dave Shea und SitePoint für den Tipp.
#wrap {overflow: hidden; border: #F08080 5px solid; margin: 0 auto; padding: 5px; width: 500px;}
Angewendet auf die äußere Box #wrap führt dies auf geradezu magische Art und Weise dazu, dass die äußere Box die beiden inneren nun vollständig umfasst.

Der Nachteil
Wie jede andere Methode zur Lösung dieses speziellen Problems hat auch diese ihren Nachteil. Werden die beiden inneren Boxen im Beispiel zu breit, werden sie wegen der hidden-Eigenschaft einfach abgeschnitten. Man sollte also genau darauf achten, den Inhalt nicht zu breit werden zu lassen.
Im folgenden Bild wurde zur Verdeutlichung das hidden durch auto ersetzt, wodurch dann horizontale Scrollbalken auftreten anstatt dass der Inhalt abgeschnitten wird.

Alles in allem halte ich dies für eine schöne und saubere Lösung, die in sehr vielen Browsern einwandfrei funktioniert.
Im Druckwesen ist die Ausrichtung von Text an einem Grundlinien-Gitter gang und gäbe. Im Web hingegen leider immer noch weitgehend unbekannt oder ungenutzt. Dabei bietet dies einige Vorteile, wie z.B. einen einheitlichen vertikalen Rhythmus für bessere Lesbarkeit.
Darüber, wie man dieses Grundlinien-Gitter mit CSS umsetzen kann, klärt der sehr informative Artikel der Opera Developer Community auf.
Zum angesprochenen Artikel.
[via Peter Kröner]