|
|
|
Cross-Browser DHTMLEigentlich ist DHTML weder eine eigene Sprache noch ein Thema für sich. Dynamic HTML ist ein Begriff für die Möglichkeit, mit HTML, CSS und JavaScript Bewegung in die ansonsten statischen HTML-Seiten zu bringen. DHTML beinhaltet somit mehrere Themen, die sich aber nur schlecht getrennt voneinander betrachten lassen, da erst ihr Zusammenspiel ermöglicht, was nachher dynamisch erscheint.
Die Probleme bei der Cross-Browser Programmierung lassen sich auf zwei Hauptursachen zurückführen: 1. Unvollständige CSS-UnterstützungDie Versionen 4.x sowohl des Netscape Navigators als auch des Internet Explorers haben den CSS-1-Standard nur lückenhaft und oft fehlerbehaftet implementiert. Insbesondere Netscape hat sich hier nicht mit Ruhm bekleckert. Der Internet Explorer 5.x sowie der neue Netscape 6 (mit der neuen Gecko-Engine) unterstützen jedoch fast das ganze Repertoire, so dass die gröbsten Probleme mit dem Aussterben der 4er-Versionen verschwinden werden. Noch ist es aber nicht so weit; und damit auch Benutzer der nicht ganz topaktuellen Browser-Generationen akzeptable Seiten präsentiert bekommen, muss man die Bugs der älteren Generation weiterhin berücksichtigen. Eine ganz ausgezeichnete Übersicht über die Macken der verschiedenen Browser finden sich in der Bug-Tabelle von www.RichInStyle.com, die so hervorragend ist, dass ich auf dieses Thema hier nur am Rande weiter eingehen werde. Eine große Macke beim Netscape Navigator sei jedoch erwähnt, nämlich die unangenehme Eigenschaft, dass dieser Browser Style Sheets "vergisst". Wer im body z.B. eine Font-Family definiert, wird bemerken, dass diese plötzlich nicht mehr berücksichtigt wird, wenn etwa eine table oder ein Absatz (p) beendet wurde. In der Tat gilt das für jedes beendete Tag! Dies lässt sich zum Glück aber vermeiden, indem jedes benutzte Tag zusammen mit dem body am Anfang definiert wird:
BODY, TD, P, EM, H1, H2, H3, H4, H5, H6, UL, OL
{font-family: Verdana, Arial, sans-serif}
Durch die Aufzählung aller verwendeten Tags wird Netscape "erinnert", dass Styles für diese definiert wurden, auch wenn diese Tags beendet werden. Die Liste sollte natürlich entsprechend erweitert werden, wenn noch andere Tags im Dokument vorkommen. Das kann einiges an Haareraufen vermeiden. 2. Unterschiedliche DOMsDie Document Object Models (DOM) von Microsoft und Netscape basieren auf unterschiedlicher Logik und müssen daher leider unterschiedlich angesprochen werden. Das DOM dient dazu, die einzelnen Elemente einer Seite für die Manipulation in JavaScript zugänglich zu machen. Das geschieht, indem dort die Seitenelemente als Objekte zur Verfügung gestellt werden, deren Attribute gelesen und/oder beschrieben und deren Methoden angewandt werden können. Auf diese Art kann man z.B. den bekannten Rollover-Effekt realisieren, bei dem beim Überfahren mit der Maus eine Grafik durch eine andere ausgetauscht wird. Momentan gilt es sogar drei verschiedene DOMs zu berücksichtigen: Die der beiden großen Browser-Konkurrenten Netscape und Microsoft, die in der Versionen 4.x implementiert sind, und das DOM, das vom W3C als Standard (als sog. Technical Recommendation: technische Empfehlung) verabschiedet wurde, und das im Internet Explorer ab Version 5 und im Netscape ab Version 6 implementiert wurde. Microsoft gewährt zwar Abwärtskompatibilität, so dass auch in den neueren Versionen noch das alte DOM unterstützt wird, aber die Engine von Netscape 6 (genannt Gecko) wurde von Grund auf neu programmiert und unterstützt konsequenterweise nur noch den W3C-Standard. Kapselung der UnterschiedeDie ganze Problematik wird etwas übersichtlicher, wenn man sich auf die wesentlichen Unterschiede konzentriert, und dafür eigene Funktionen strickt. Diese Funktionen kümmern sich zentral um die Unterschiede in den DOMs, während sie nach außen eine einheitliche Schnittstelle unabhängig vom zugrunde liegenden DOM zeigen. Diese Vorgehensweise nennt man Kapselung. Ihr größter Vorteil ist, dass bei einer Änderung des DOMs nur die Funktion selbst anzupassen ist, während alle Scripts, die man inzwischen unter Verwendung der Funktion geschrieben hat, unverändert bleiben können. Statt an Dutzenden Stellen muss also nur an einer Stelle geändert werden. Layers und DIVsDen größten Unterschied findet man in der Behandlung von Layers. Layers sind Teile des Dokuments, die unabhängig vom Rest positioniert werden können. Sie können sogar wie Cels (Folien) beim Erstellen von Trickfilmen transparent übereinander gelegt werden. Diese Idee wurde mit Netscapes LAYER Tag geboren, und Microsoft zog bald nach, nannte das Tag jedoch natürlich anders und baute es auch anders in sein DOM ein. Das Tag ist nach W3C-Standard DIV und LAYER wird auch in Netscape 6 nicht mehr unterstützt, aber der Begriff ist so sprechend, dass man meist weiterhin von Layers spricht. Für Netscape war ein Layer ein Teil des Hauptdokuments, das wiederum selbst ein Dokument beinhaltete. Daraus folgte die Syntax beim Zugriff über JavaScript: document.layers[0].document.images[2].src = "img/other.gif"; document.layers[0].visibility = "visible"; Bemerkenwert ist, dass ein Layer kein Style-Attribut besitzt, sondern direkt selbst über ein Attribut visibility verfügt. Die Layers sind dabei in einem Vektor angeordnet, also durchnummeriert. Microsoft ging da ganz anders vor: Das Attribut all beinhaltet alle Layers, auf die direkt zugegriffen werden kann, wenn man den Namen kennt. Man tut also gut daran, seinen Layers einen Namen zu geben, zumal über den auch ein Zugriff bei Netscape möglich ist. Nennen wir unseren Layer also "Test1", dann können wir ihn direkt ansprechen. Sowohl im Internet Explorer... document.all.Test1.document.images[2].src = "img/other.gif"; document.all.Test1.style.visibility = "visible"; ...als auch im Netscape Navigator... document.Test1.document.images[2].src = "img/other.gif"; document.Test1.visibility = "visible"; Leider bietet uns der W3C-Standard die Zugriffsmöglichkeit direkt über den Layer-Namen als Attribut des Dokuments nicht. Zum Glück wurde aber eine Methode aus dem DOM-2 implementiert, die uns aus der Patsche hilft: document.getElementById(). Für einen W3C-konformen Browser sieht das also so aus:
document.images[2].src = "img/other.gif"; // ohne Layer
document.getElementById("Test1").style.visibility = "visible";
Die Lösung von det janzeAlso alles ganz ähnlich, aber eben doch nicht ganz gleich... Basteln wir uns also eine Funktion, die das ganze Tohuwabohu für uns kapselt, auf dass wir uns nie wieder darum kümmern brauchen:
// 1. Funktion fuer den Zugriff aufs Dokument
function DivObjDocument(div_id)
{
if (!div_id || div_id.length==0) {
div_obj = document;
}
else {
if (document.getElementById) {
div_obj = document; // W3C
}
else if (document.layers) {
div_obj = eval("document."+div_id+".document");
}
else if (document.all) {
div_obj = eval("document.all."+div_id+".document");
}
}
return div_obj;
}
// 2. Funktion fuer den Zugriff aufs Style Sheet
function DivObjStyle(div_id)
{
if (!div_id || div_id.length==0)
{
if (document.getElementById) {
div_obj = document.style;
}
else if (document.layers) {
div_obj = document;
}
else if (document.all) {
div_obj = document.all.style;
}
}
else {
if (document.getElementById) {
div_obj = document.getElementById(div_id).style;
}
else if (document.layers) {
div_obj = eval("document."+div_id);
}
else if (document.all) {
div_obj = eval("document.all."+div_id+".style");
}
}
return div_obj;
}
Damit können wir ohne Ansehen des Browsers oder des DOMs so zugreifen:
DivObjDocument("Test1").images[2].src = "img/other.gif";
DivObjStyle("Test1").visibility = "visible";
Auch wenn keine Layers verwendet werden, können diese Funktionen verwendet werden, indem einfach als Layer-Name nichts mitgegeben wird, z.B. DivObjDocument().images[2].src, so dass es auch kein Problem darstellt, wenn das Dokument später doch noch in einen Layer gepackt werden soll. |
|||||||||||||||||||