# DHTML

Es gibt heute viele, die es statt mit Dynamik mit Hektik versuchen.

# HTML wird dynamisch

DHTML ist eine Abkürzung für Dynamic Hypertext Markup Language (dt. dynamische Hypertext-Auszeichnungssprache) und bezeichnet keinen neuen Sprachstandard, sondern eine Kombination von JavaScript bzw. Scriptsprachen und HTML, die eine dynamische Änderung bzw. den dynamischen Aufbau eines HTML-Dokuments ermöglichen. Weit verbreitet ist die Annahme, dass DHTML ein Werbebegriff und eine Erfindung von Marketingstrategen sei. Dies stimmt jedoch nicht, denn DHTML basiert auf tief gehenden Erweiterungen von HTML. Einschwebender Text, aufklappbare Navigationsleisten oder Elemente, die sich aufgrund von Benutzeraktionen verändern, sind DHTML-Effekte, die Sie im Internet häufig antreffen werden. Ein kleines Beispiel:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- DHTML //-->
<html>
  <head>
    <title>DHTML</title>
  </head>
  <body>
    <p id="DHTML" onClick="document.getElementById('DHTML').firstChild.nodeValue='Danke'">Bitte anklicken</p>
  </body>
</html>

Listing 8.1: DHTML-Effekt, der den Text eines Absatzes verändert, sobald der Benutzer diesen anklickt

Die eben genannten Effekte müssen aber nicht zwangsläufig auf DHTML basieren. Sie lassen sich auch mit JavaApplets oder Flash-Filmen erzeugen. Wenn Sie aber genau aufpassen, wird Ihnen schnell auffallen, welcher der Effekte ein DHTML-Effekt ist und welcher nicht. Immerhin zeigen JavaApplets eine Meldung an, dass sie geladen werden, und Flash-Filme sind oft mit einer Animation während des Ladevorgangs versehen.

# Kompatibilität

Zwar funktioniert dynamisches HTML mit Netscape und dem Internet Explorer ab der Version 4, jedoch konnten es sich beide Hersteller nicht nehmen lassen, vollkommen andere Wege in der Implementierung zu gehen. Die oft genannte proprietäre Layer-Technik von Netscape, die ihren Ursprung in den Anfängen von DHTML nahm, funktioniert nur mit einem Netscape-Browser und obendrein nur mit der Version 4.x. Seit der Version 6 interpretiert der Netscape-Browser layer-Elemente nicht einmal mehr. Der Internet Explorer dagegen hat layer-Elemente noch nie berücksichtigt oder gar interpretiert. Diese fehlende Kompatibilität führt dazu, dass DHTML einen fahlen Beigeschmack bekommt. Immerhin ist es oft notwendig, Scripts an den Netscape-Browser und an den Microsoft-Browser anzupassen, was zwangsläufig zu doppelter Arbeit führt, da die DHTML-Modelle beider Browser grundverschieden und inkompatibel sind.

Ein Lichtblick an Horizont ist das DOM (engl. Document Object Model), das vom W3-Konsortium entwickelt und normiert wurde. Es bildet einen einheitlichen Standard dafür, wie die Elemente eines HTML-Dokuments mit Scriptsprachen anzusteuern sind. Viele der neuen Browserversionen setzen das W3C-DOM schon sehr gut in JavaScript um, auch wenn oftmals noch Schwächen zu entdecken sind. Es wird aber in Zukunft wesentlich einfacher werden, in jedem Browser funktionierendes DHTML zu programmieren.

# Internet Explorer-DOM

Wie bereits erwähnt, gibt es hinsichtlich DHTML zwischen den Browsern Unterschiede. So verfügen sowohl der Internet Explorer als auch der Netscape-Browser über ein eigenes Document Object Model. Dabei ist der Microsoft-Browser dem Konkurrenten von Netscape mehr als eine Nasenlänge voraus. Immerhin bietet er durch unterschiedliche Möglichkeiten einen sehr einfachen Zugriff auf die Elemente. Generell gilt aber, dass er bereits seit der Version 4 das proprietäre DOM zur Verfügung stellt.

Um also Zugriff auf benannte Elemente eines Dokuments zu erhalten, hat Microsoft kurzerhand das document-Objekt um ein Kindobjekt erweitert, nämlich um das Objekt all.

Nun stehen Ihnen drei Wege zur Verfügung, um auf ein benanntes Element zuzugreifen:

document.all.titel.innerText = "Neuer Text";  
document.all("titel").innerText = "Neuer Text";  
document.all["title"].innerText = "Neuer Text";

Allen drei Varianten ist gemeinsam, dass sie den Text im Gültigkeitsbereich des Elements, dessen id-Attribut den Wert titel enthält, durch »Neuer Text« ersetzen. Der Grund für die Vielfalt der Möglichkeiten liegt in der internen Verwaltung der HTML-Elemente durch den Internet Explorer. Grundsätzlich existiert zu jedem Element im HTML-Dokument ein Objekt im DOM. Auf dieses Objekt können Sie nun direkt über den Objekt-Bezeichner zugreifen (Zeile 1), und zwar über eine Methode, der Sie den Objektnamen als Parameter übergeben (Zeile 2), oder über ein assoziatives Array, das alle HTML-Elemente enthält und als Index den Bezeichner des Objekts erwartet (Zeile 3). Die Eigenschaft innerText kann gelesen und geschrieben werden und enthält den Text, der im Browser dargestellt wird (also den ausgezeichneten Text). Zusätzlich steht noch eine Kurzform zur Verfügung. Diese bezieht sich auf das Ansprechen des Elements als Objekt. Anstelle von

document.all.titel.innerText = "Neuer Text";

können Sie nämlich auch

titel.innerText = "Neuer Text";

schreiben.

Sowohl das Objekt all als auch die Methode all() und das assoziative Array all[] stehen nur im Internet Explorer und in keinem anderen Browser zur Verfügung.

# Netscape-DOM

Während der Netscape Navigator 4.x über ein eigenständiges DOM verfügt, ist der Netscape ab Version 6 direkt mit dem DOM vom W3C verknüpft. Über DHTML im Netscape 6 erfahren Sie mehr im nächsten Kapitel 29, Was sonst noch wichtig ist. Hier folgt erst einmal nur die Behandlung des Netscape Navigators 4.x.

Im Netscape Navigator 4.x gibt es nur eine Möglichkeit, um auf benannte Elemente zuzugreifen, und die ist nicht besonders komfortabel. Neben der Beschränkung auf bestimmte Elementtypen muss die Benennung des Elements mit dem name-Attribut erfolgen (im Gegensatz zum IE).

Elemente eines Typs werden durch ein assoziatives Array dargestellt. Als Index geben Sie dabei den Wert an, der im name-Attribut des entsprechenden Elements angegeben wurde.

document.layer["titel"].bgcolor = "#FF0000";

Dieses Beispiel setzt voraus, dass ein layer-Element mit dem Wert titel im name-Attribut existiert, z. B.:

<layer name="titel" bgcolor="#0000FF">Ein Layer</layer>

Der Knackpunkt ist, dass Sie den Text eines Layers nicht ohne größeren Aufwand ändern können. In den meisten Fällen wird der Netscape Navigator sogar abstürzen, da Sie das Dokument zum Schreiben öffnen müssen. Es ist jedoch möglich, und das Verfahren wird in Listing 8.2 dargestellt.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- DHTML im Netscape Navigator 4.x //-->
<html>
  <head>
    <title>DHTML im Netscape Navigator 4.x</title>
    <script type="text/javascript">
    <!--
      function layerAendern()
      {
        document.layers[0].document.open();
        document.layers[0].document.clear();
        document.layers[0].document.write("Ein neuer Text");
        document.layers[0].document.close();
      }
    //-->
    </script>
  </head>
  <body>
    <layer>Beliebiger Text</layer><br>
    <a href="javascript:layerAendern()">Text des Layers &auml;ndern</a>
  </body>
</html>

Listing 8.2: Dynamisches Ändern eines Layers im Netscape Navigator 4.x

Der Grund, warum das Listing 8.2 nur im Netscape Navigator 4.x funktioniert, ist, dass der Netscape Navigator 4.x jeden Layer in einem HTML-Dokument wie ein eigenes Browserfenster behandelt. Zuerst wird also mittels document.layers[0] der erste Layer im HTML-Dokument angesprochen. Wie bei jedem Browserfenster bzw. Dokument stellt der NN 4.x auch einem Layer ein eigenes document-Objekt zur Verfügung. Mit den Methoden open() und clear() wird zuerst der Layer zum Schreiben geöffnet und anschließend dessen Inhalt gelöscht. Mit der Methode write() wird nun neuer Inhalt in den Layer eingefügt, und anschließend wird der Layer mit der Methode close() wieder geschlossen. Je öfter Sie solche Operationen durchführen, desto wahrscheinlicher wird es, dass der Browser abstürzt.

Übrigens funktioniert das Beispiel nur in einem Netscape Navigator der Version 4 (z. B. 4.05, 4.06 oder 4.78), nicht aber im Netscape 2, 3, 6 oder gar im IE oder Opera.

# W3C-DOM

Das DOM des W3C sieht eine allgemeine Richtlinie für Objektmodelle in Browsern vor und legt fest, wie mittels JavaScript darauf zugegriffen werden soll. Da dies jedoch nur eine Empfehlung seitens des Konsortiums ist, halten sich zwar die meisten Browserhersteller daran, sind aber nicht immer sehr genau in deren Umsetzung. Der Opera-Browser z. B. kennt zwar das W3C-DOM, aber der größte Teil der Objekte und Methoden, die zur Verfügung gestellt werden, funktioniert nicht.

Das DOM des W3C geht einen anderen Weg, auch wenn sich dieser nicht allzu sehr von dem des Internet Explorers unterscheidet. Während das Internet Explorer-DOM alle Elemente in Objektlisten zur Verfügung stellt, die direkt angesprochen werden können, bildet das W3C-DOM aus den Elementen eine Baumstruktur. So werden Kindelemente als Verzweigungen von Elternelementen dargestellt. Für den Zugriff auf die Elemente bedeutet dies lediglich, dass Sie anstelle von

document.all

eine der folgenden Anweisungen verwenden:

document.getElementById()  
document.getElementsByName()  
document.getElementsByTagName()

Der Unterschied zwischen diesen Möglichkeiten besteht darin, wie das Element identifiziert wird: entweder über den Wert des id-Attributs, den Wert des name-Attributs oder über den Elementtyp.

Bei Verwendung der Methode getElementById() muss der Wert des id-Attributs des Elements, das angesprochen werden soll, dokumentweit eindeutig bzw. einmalig sein. Die Methode getElementsByName() verlangt die dokumentweite Eindeutigkeit beim Wert des name-Attributs eines Elements nicht. Ganz anders funktioniert der Zugriff, wenn Sie die Methode getElementsByTagName() verwenden. Mit dieser Methode können Sie einen bestimmten Elementtyp ansprechen (z. B. input oder div) und müssen lediglich angeben, an wievielter Stelle das Element steht. Haben Sie in einem HTML-Dokument z. B. fünf div-Elemente verwendet, werden diese nach der Reihenfolge ihrer Definition im HTML-Dokument über einen Index angesprochen. Das div-Element, das als zweites im HTML-Dokument definiert wurde, besitzt dementsprechend den Index 1, das vierte div-Element den Index 3 usw.

Alle Elemente, Attribute und Texte eines HTML-Dokuments werden im W3C-DOM als Knoten bezeichnet, von denen es drei Typen gibt: Elementknoten, Attributknoten und Textknoten. Das folgende Beispiel soll dies verdeutlichen:

<p id="absatz">Textabsatz</p>

Insgesamt verfügt diese Zeile im W3C-DOM über vier Knoten. Der erste Knoten ist ein Elementknoten, der aus dem p-Element resultiert. Der zweite Knoten ist ein Attributknoten, der auf dem id-Attribut basiert. Die Knoten drei und vier sind Textknoten und basieren einmal auf dem Wert des id-Attributs (absatz) und einmal auf dem Text im Gültigkeitsbereich des p-Elements (Textabsatz). Anstatt nun den Wert einer Eigenschaft wie z. B. innerHTML oder innerText zu ändern, verwenden Sie das Kindobjekt firstChild und die Eigenschaft nodeValue.

document.getElementById('absatz').firstChild.nodeValue = 'Neuer Text';

Diese Zeile würde den Text des p-Elements aus dem vorangegangenen Beispiel ändern bzw. ersetzen. Ein vollständiges Beispiel könnte wie folgt aussehen:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- DHTML nach W3C //-->
<html>
  <head>
    <title>Listing 8.3</title>
    <script type="text/javascript">
    <!--
      function change()
      {
        document.getElementById('head1').firstChild.nodeValue = 'Danke';
      }
    //-->
    </script>
  </head>
  <body>
    <h1 id="head1" onClick="change()">Klick mich an</h1>
  </body>
</html>

Listing 8.3: Bei einem Mausklick auf das h1-Element ändert sich der Text der Überschrift

Während Element- und Textknoten immer Kinder eines übergeordneten Elementknotens sind, sind Attributknoten assoziierte Knoten. Der Zugriff auf Attribute eines Elements erfolgt deshalb anders. Das Attribut, das geändert werden soll, wird als Eigenschaft notiert.

document.getElementById('absatz').[Eigenschaft] = [Wert];

Das folgende Beispiel ändert die Ausrichtung des h1-Elements, sobald mit der Maus darauf geklickt worden ist.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- DHTML nach W3C //-->
<html>
  <head>
    <title>Listing 8.4</title>
    <script type="text/javascript">
    <!--
      function change()
      {
        if(document.getElementById('head1').align == 'right')
        {
          document.getElementById('head1').align = 'left';
        }
        else
        {
          document.getElementById('head1').align = 'right';
        }
      }
    //-->
    </script>
  </head>
  <body>
    <h1 id="head1" align="left" onClick="change()">Klick mich an</h1>
  </body>
</html>

Listing 8.4: Sobald ein Anwender mit der Maus auf das h1-Element klickt, wird dessen Ausrichtung geändert.

# Problematik und Lösung

All diese verschiedenen DOM-Varianten wirken sich nachteilig auf die Kompatibilität aus. Dies führt zwangsläufig dazu, dass Sie Ihre DHTML-Scripts an jeden Browser anpassen müssen. Dazu muss jedoch erst einmal der Browser ermittelt und geklärt werden, welches DOM dieser unterstützt. Eine pragmatische Möglichkeit ist es, einfach zu testen, auf welches DOM der Browser reagiert.

Sie müssen also feststellen, ob der Browser das Internet Explorer-DOM, das Netscape Navigator 4.x-DOM oder das W3C-DOM unterstützt. Für den NN4.x fragen Sie einfach das document.layers-Objekt ab. Wenn der Rückgabewert true ist, handelt es sich um den Netscape Navigator 4.x. Für den Internet Explorer fragen Sie das document.all-Objekt ab. Bei true handelt es sich um den IE. Da sowohl der Netscape 6 als auch der Internet Explorer 5.x das W3C-DOM unterstützen, müssen Sie lediglich das Objekt document.documentElement abfragen, um festzustellen, ob es sich um einen dieser beiden Browser handelt.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- Welches DOM //-->
<html>
  <head>
    <title>Listing 8.5</title>
  </head>
  <body>
    <script type="text/javascript">
    <!--
      n4 = document.layers;
      ie = document.all;
      w3c = document.documentElement;

      if(n4) document.write("Netscape<br>");
      if(ie) document.write("Internet Explorer<br>");
      if(w3c) document.write("W3C kompatibel");
    //-->
    </script>
  </body>
</html>

Listing 8.5: JavaScript, um zu ermitteln, welches DOM der Browser des Benutzers unterstützt

Das Script in Listing 8.5 stellt auf relativ sichere Art und Weise fest, welcher Browser vom Benutzer verwendet wird. So sind Sie in der Lage, zwischen Netscape Navigator 4.x, Internet Explorer und Netscape 6 zu unterscheiden und entsprechend in Ihrem DHTML-Script darauf zu reagieren.

# Ausklappbare Navigationsleiste

Ich möchte Ihnen nun ein Beispiel für einen typischen DHTML-Effekt zeigen: eine ausklappbare Navigationsleiste. Das folgende Beispiel funktioniert sowohl im Internet Explorer als auch im Mozilla ab Version 1.0, Netscape ab Version 6 und Opera ab Version 5.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- ausklappbare Navigationsleiste //-->
<html>
  <head>
    <title>Listing 8.6</title>
    <script type="text/javascript">
    <!--
      var n4, ie, w3c;

      function init()
      {
        n4 = document.layers;
        ie = document.all;
        w3c = document.documentElement;
      }

      function showNav()
      {
        if(ie)
        {
          document.all.naviBar.style.visibility = 'visible';
        }
        else if(w3c)
        {
          document.getElementById('naviBar').style.visibility = 'visible';
        }
        else
        {
          alert('Diese Seite ist mit Ihrem Browser nicht kompatibel');
        }
      }

      function hideNav()
      {
        if(ie)
        {
          document.all.naviBar.style.visibility = 'hidden';
        }
        else if(w3c)
        {
          document.getElementById('naviBar').style.visibility = 'hidden';
        }
        else
        {
          alert('Diese Seite ist mit Ihrem Browser nicht kompatibel');
        }
      }

    //-->
    </script>
    <style type="text/css">
      <!--
        body        { margin-left:40px; }
        #leftBorder { background-color:#336699;
                      width:25px; height:100%;
                      position:absolute;
                      left:0px; top:0px; }
        #naviBar    { background-color:#336699;
                      width:150px; height:250px;
                      position:absolute;
                      left:0px; top:50px;
                      padding:5px;
                      visibility:hidden; }
        a           { color:#FFFFFF; }
      //-->
    </style>
  </head>
  <body onLoad="init()">
    <div id="leftBorder" onMouseOver="showNav()" onMouseOut="hideNav()">
    </div>
    <div id="naviBar" onMouseOver="showNav()" onMouseOut="hideNav()">
      <a href="http://www.galileo-press.de/">Galileo Press</a><br>
      <a href="http://www.google.de/">Google</a><br>
      <a href="http://www.my-galileo.de/">My-Galileo</a>
    </div>
    <h1>Ausklappbare Navigationsleiste</h1>
    <p>Wenn Sie den Mauscursor an den linken Seitenrand bewegen, klappt die Navigationsleiste auf und Sie k&ouml;nnen einen Verweis anklicken.</p>
  </body>
</html>

Listing 8.6: Eine ausklappende Navigation mit HTML, JavaScript und CSS

Im HTML-Dokument wurden zwei div-Elemente definiert. Das erste div-Element ist der sensitive Bereich, der das Aufklappen der Navigationsleiste bewirkt. Das zweite div-Element ist die eigentliche Navigationsleiste. Zu Beginn ist diese unsichtbar, und sie wird erst sichtbar, wenn der Benutzer die Maus über das div-Element am linken Fensterrand bewegt.

Beim Laden des Dokuments wird die Funktion init() ausgeführt, die die Variablen n4, ie und w3c entweder auf true oder auf false setzt. Sobald die Maus über das div-Element am linken Fensterrand bewegt wird, führt der Event-Handler onMouseOver die Funktion showNav() aus. In dieser Funktion werden die Variablen n4, ie und w3c auf den Wert true überprüft. Sobald eine dieser Variablen den Wert true besitzt, wird die entsprechende Variante zum Ansprechen eines Elements verwendet. Die CSS-Eigenschaft visibility des div-Elements mit dem Wert naviBar im id-Attribut wird dann auf visible gesetzt. Verliert eines der beiden div-Elemente den Mausfokus, wird die Eigenschaft visibility wieder auf hidden gesetzt.

Möchten Sie dynamisch Eigenschaften eines Elements ändern, die auf CSS basieren, dürfen Sie keine Bindestriche verwenden und müssen den ersten Buchstaben nach dem Bindestrich groß schreiben. So wird background-color zu backgroundColor, text-align zu textAlign und line-spacing zu lineSpacing.

# Zusammenfassung

  • DHTML ist die Abkürzung von »Dynamic HTML« und ist kein eigener Standard, sondern die Zusammenarbeit von HTML, JavaScript und dem DOM.
  • DOM ist die Abkürzung für »Document Object Model«. Man unterscheidet im Allgemeinen zwischen drei Varianten: dem DOM des Internet Explorers, dem des Netscape Navigators 4 und dem des W3C.
  • Durch diese drei Varianten entstehen verschiedene Probleme. Das größte Problem ist die fehlende Kompatibilität zwischen den einzelnen Browsern.

# Fragen und Übungen

  1. Welche drei Möglichkeiten stehen im Internet Explorer zur Verfügung, um auf ein Element im HTML-Dokument zuzugreifen?
  2. Welche Möglichkeiten offeriert das W3C-DOM, um auf Elemente des HTML-Dokuments zuzugreifen?
  3. Wie lässt sich DHTML im Netscape Navigator 4.x umsetzen?