Coding-Schatzkästlein
Kleine Tips & Scripts zum Webdesign
Start > DHTML > Darstellungswechsel

DHTML: Darstellungswechsel
(Un-/Sichtbare Elemente: Ein-/Ausklappen, Verstecken, Transparenz, Farbe)

Zusammenfassung

Name:  Toggle Element(s)
Aufgabe:  Ermöglicht die wechselweise Manipulation der Darstellung einzelner HTML-Elemente oder ganzer Seitenbereiche wie Absätze oder Tabellen(-zeilen/-spalten).
Benötigt:  JavaScript 1.5 (gesichert, nicht gesichert für JavaScript 1.0)
Beispiel:  toggle("unfold","ID1")
toggle("fold","tr","Typ")
toggle("hide","div","Typ") toggle("trans:75","ID1") toggle("color","p","Typ")
Download:  toggle.zip

Mittels CSS können Browser HTML-Elemente unterschiedlich darstellen. U.a. können sie Elemente/Layer/Ebenen auch verstecken - sowohl mit Platzhalter (Style: visibility), als auch ohne (Style: display). Manche Browser können HTML-Elemente sogar durchsichtig darstellen - wie der Internet Explorer (Style: filter("Alpha")), die auf Mozilla (Style: -moz-opacity) und KHTML (Style: -khtml-opacity) basierenden Browser wie Konqueror (Unix - leider nur eingeschränkt) oder Safari (Macintosh & Windows). Zukünftig sollen es aber alle Browser sein, die CSS Version 3 unterstützen (Style: opacity - wird ebenfalls in den aktuellen Versionen einiger Browser unterstützt, z.B. im Firefox oder Safari). Das "normale" Darstellungsvarianten wie Vorder- (Style: color) bzw. Hintergrund- (Style: background-color) und Rahmenfarbe (Style: border-color) gesetzt werden können, versteht sich ohnehin von selbst.

In Verbindung mit JavaScript kann man dies auch leicht gezielt und interaktiv nutzen. Eine Möglichkeit dazu: Man kann ein HTML-Element mit einer ID versehen und es über diese ID ansprechen. Da die ID jedoch eindeutig zu sein hat (also im Dokument nicht mehrfach vorkommen darf), müsste man nicht nur alle betreffenden Elemente mit einer einzigartigen ID versehen, sondern diese auch noch jeweils einzeln mit JavaScript ansprechen. Die hier vorgestellte Funktion toggle() ermöglicht es hingegen, nicht nur gezielt einzelne Elemente mittels ID zu manipulieren, darüberhinaus können auch mehrere Elemente mittels einer frei definierbaren Kennung auf einen Schlag bearbeitet werden. So können z.B. in einer Tabelle alle Zeilen eines bestimmten Inhaltes (oder sogar mit mehreren bestimmten Inhalten) mit einer einzigen Anweisung manipuliert werden. Zusätzlich kann man auch noch Ausnahmen festlegen, die komplementär, also gegensätzlich, bearbeitet werden. So ist es z.B. mit nur einer Anweisung möglich, bestimmte Elemente zu falten und die anderen gleichzeitig zu entfalten.

Der erste Parameter type enthält den gewünschten Befehl, den toggle() ausführen soll (nicht case-sensitive, also unabhängig von Groß/Kleinschreibung). Zur Zeit sind dies:

  1. Absolute Aktionen (mit feststehenden Werten):
    • fold faltet Elemente, d.h. sie werden ohne Platzhalter versteckt.
    • unfold stellt mit fold versteckte Elemente wieder dar.
    • hide versteckt Elemente mit einem Platzhalter.
    • unhide stellt mit hide versteckte Elemente wieder dar.
    Mangels Notwendigkeit werden ihnen (im allgemeinen) keine zusätzlichen Werte übergeben.
  2. Bedingte Aktionen (mit optionalen Werten):
    • trans stellt Elemente halb-transparent dar.
    • color setzt die Vordergrundfarbe der Elemente auf schwarz.
    • back setzt die Hintergrundfarbe der Elemente auf weiß.
    • border setzt die Rahmenfarbe der Elemente auf schwarz.
    Hier sind Werte vordefiniert - eigene Werte können aber mit einem : angehängt werden
  3. Spezielle Aktionen:
    • test überprüft, ob der Browser geeignet ist.

Man kann auch mehrere (sich nicht widersprechende) Aktionen kombinieren, so daß z.B. mit "unfold unhide" in einem Durchgang alle Elemente auf jeden Fall dargestellt werden, egal ob sie vorher gefaltet, oder nur versteckt waren.

Anmerkung zu unfold: Um ein gefaltetes Element wieder sichtbar zu machen, löscht toggle() den Wert der verwendeten CSS-Eigenschaft display (display=""). So kann man allerdings nur Elemente entfalten, wenn sie vorher auch mit JavaScript gefaltet wurden, aber leider nicht, wenn dies direkt via Style-Angabe geschah (style="display:none"). Zwar sollte man i.d.R. nur mit JavaScript falten, damit sichergestellt ist, daß Browser ohne JavaScript alles darstellen, während man bei JavaScript-Browsern davon ausgehen kann, daß sie auch entfalten können, was sie vorher selbst gefaltet haben, aber die Ausnahme bestätigt bekanntlich die Regel. ;-) Wurde aber nur mit CSS gefaltet, muß explizit die gewünschte Darstellungsart übergeben werden, indem man hinter der gewünschten Aktion, durch einen Doppelpunkt getrennt, auch die gewünschte Darstellungsart übergibt! Diese Darstellungsarten sind: block, inline, list-item, marker, run-in bzw. compact, sowie table, inline-table, table-row, table-row-group, table-header-group, table-footer-group, table-column, table-column-group und table-caption (für eine Beschreibung dieser Darstellungsarten s. den entsprechenden Eintrag in selfHTML) - ein Aufruf sähe also z.B. so aus: toggle("unfold:inline","ID1"). Leider ist dies jedoch nicht mehr so trivial, da der Internet Explorer sich hier nicht nach dem (vollen) Standard richtet (jedenfalls bis zum IE 7 inkl.)! So ist z.B. die Darstellungsart einer Tabellenzeile (<tr>) table-row - der IE kennt diese Art aber erst ab Version 8 und braucht in älteren Versionen block, was von den anderen Browsern (zurecht) falsch dargestellt wird (die im IE erlaubten Darstellungsarten sind unter MSDN Library: display nachzulesen). Um eine Tabellenzeile <tr id="ID1" style="display:none"> zu entfalten, müsste der Aufruf also toggle("unfold:"+((is_ie && agt_ieVersion<8)?"block":"table-row","ID1")) lauten (IEs bis Version 7 bekommen block, alle anderen Browser table-row), mit is_ie=true, falls der Browser ein IE ist (s. Systemvariable - viele im Internet zu findende JavaScripts zur Browsererkennung arbeiten leider ungenau und meinen selbst dann einen IE zu erkennen, wenn der Browser ein anderer ist, da oft nur auf das Vorhandensein von document.all und/oder die Browserkennung geprüft wird, was beides, selbst in Kombination, nicht ausreichend ist; und die Browserversion selbst ist so trotzdem nicht definitiv zu ermitteln, da beim IE JScript- & Browserversion unabhängig voneinander sind)!
Aber aufgepaßt: Wenn sich der IE 8 im "Kompatibilitätsmodus" befindet (ist automatisch der Fall, wenn die Seite im Quirks-Modus läuft, oder der Browser mittels X-UA-Compatible dazu angewiesen wird), dann gilt natürlich auch beim IE ab 8: Nur block & inline!

Soll die Darstellung einer bedingten Aktion vom voreingestellten Wert abweichen, kann man auch eigene Werte anhängen. Für z.B. eine Transparenz von 25% und eine rote Vordergrundfarbe müsste der Aufruf toggle("trans:25 color:red","ID1") lauten. Werden Ausnahmen für eine komplementäre Darstellung definiert, so kann man optional nach einem / einen eigenen Komplementär-Wert anhängen (bei Komplementär-Darstellung mit 75% Transparenz und blauer Vordergrundfarbe also trans:25/75 color:red/blue).

Bei der Transparenz sind Werte im Bereich von 0 (keine Transparenz) bis 100 (volle Transparenz - das Element ist unsichtbar) möglich, bei den Farben die in CSS auch sonst gültigen Werte (also vordefinierten Farbnamen, aber z.B. auch hexadezimale RGB-Werte wie #FF0000 für rot).

Die Art, wie toggle() die gewünschte Aktion abarbeitet, hängt dann vom zweiten Parameter ab:

  1. toggle(type,element)
    Wenn der zweite Parameter element eine (im Dokument vorhandene) ID ist, dann wird gezielt dieses Element bearbeitet. Um also z.B. den Text <p id="Absatz1">Dies ist Absatz 1!</p> ohne Platzhalter zu verstecken (zu falten), bedarf es der Anweisung toggle("fold","Absatz1");, was, inkl. Plausibilitätsprüfung, dem JavaScript-Code if(document.getElementById && document.getElementById("Absatz1")) { document.getElementById("Absatz1").style.display="none"; } entspricht. Analog kann man mit toggle("unfold","Absatz1"); den Text wieder erscheinen lassen.
  2. toggle(type,element,toggleID[,xID[,xID[,...[,xSwitch]]]])
    Ist der zweite Parameter element keine vorhandene ID, so wird er als HTML-Tag interpretiert! Also liessen sich z.B. mit "tr" mehrere Tabellenzeilen, mit "p" mehrere Absätze auf einen Schlag bearbeiten.
    Um festzulegen, welche Elemente bearbeitet werden sollen, dient dann der dritte Parameter toggleID, der eine vom HTML-Autor zu definierende Basiskennung enthalten muß. Optional können anschließend beliebig viele Teilkennungen übergeben werden, um auch Ausnahmen bestimmen zu können. Dies kann entweder in getrennten Parametern geschehen ("A","B",...), oder in einer einzigen Zeichenkette, wobei die Restkennungen dann mittels Pipe-Symbol voneinander getrennt werden müssen ("A|B|...").
    Der letzte, ebenfalls optionale Parameter xSwitch definiert dann noch, wie mit diesen Ausnahmen verfahren werden soll. Voreingestellt ist false, wobei die Ausnahme-Elemente einfach ignoriert werden. Ist xSwitch hingegen true, so wird auf die Ausnahme-Elemente die jeweilige Komplementärfunktion angewendet. D.h., wird z.B. bei toggle("fold",...) ein Element gefunden dessen Toggle-Attribut mit einer passenden Basiskennung beginnt, so wird dieses Element gefaltet. Wurde aber dessen Restkennung als Ausnahme übergeben, so wird es nicht gefaltet. Wenn xSwitch true ist, so wird es sogar explizit entfaltet.

Um mehrere Elemente in einem Durchgang bearbeiten zu können (Variante 2), wird in allen betroffenen Elementen ein HTML-Attribut benötigt, das als Wert (mindestens) eine Basiskennung hat, die in toggleID übergeben werden muß. Jedes so ausgezeichnete Element wird also beim Aufruf von toggle("fold",...) gefaltet. Voreingestellt ist der (erfundene) Attributname gid (Group-ID), aber man kann sich in der Routine auch einen anderen Attributnamen definieren (var toggleAttribute="..."). Außerdem kann man auch direkt einen spezifischen Attributnamen übergeben! Er kann, getrennt durch einen Doppelpunkt, an den Tagnamen gehängt werden (tr:id bearbeitet z.B. alle Tabellenzeilen anhand des Inhalts des ID-Attributs).

Anmerkung: Auch wenn die Browser-Hersteller fleissig Tags & Attribute jenseits der HTML-Standards des W3Cs erfinden: Ein Standard-konformer HTML-Validator wird die Anwendung des erfundenen Attributes gid natürlich bemängeln. Erst mit XML ist es möglich, beliebige eigene Attribute valide zu definieren. Stören muß dies jedoch nicht, da das HTML-Dokument trotzdem wohlgeformt bleibt (und das ist das Entscheidende für einen HTML-Browser - s. Know-how).
Die Anwendung bereits vorhandener HTML-Attribute ist nicht unbedingt eine gute Lösung. Je nach Browser kann es dabei zu Fehlern kommen: Bei Verwendung von name (ein thematisch zwar passendes, aber laut dem W3C nur in wenigen Tags erlaubtes Attribut) gibt es Probleme mit Opera-Browsern, die Verwendung von class (fast überall erlaubt und durch gleichzeitige CSS-Definitionen für unterschiedliche Inhalte ggf. ohnehin sinnvoll) bereitet hingegen dem Internet Explorer Probleme (wohlgemerkt stets mit der hier verwendeten JavaScript-Methode getAttribute() =:-o).
Zumindest die Verwendung von id macht keinerlei Probleme, hat dafür aber natürlich den Nachteil, daß man nicht gleiche IDs vergeben darf, und somit ein Teil der Funktionalität von toggle() auf der Strecke bleibt. Gleichwohl ist id vorzuziehen, wenn man mit der eingeschränkten Funktionalität auskommt und unbedingt nach den HTML-Standards des W3Cs coden möchte.

Besonders wenn viele Elemente durchsucht, aber nur wenige wirklich bearbeitet werden müssen, kommt es zu eigentlich unnötigen Wartezeiten. Um dem ggf. entgegenzuwirken, kann man dem gewünschten Tagnamen noch einen Arbeitsbereich mitgeben (in geschweiften Klammen). Hat nämlich eine HTML-Seite beispielsweise 1000 TR-Elemente, so müssen alle diese Elemente auf das passende Attribut hin durchsucht werden, selbst wenn es sich um unterschiedliche Tabellen handelt. Wenn aber z.B. nur die Tabelle Nr. 2 interessant ist, deren TR-Elemente in der Seite die (fortlaufenden) internen Nummern 50-99 besitzen (es wird bei 0 begonnen zu zählen), so kann man die Suche mit tr{50-99} auf den gewünschten Bereich beschränken (bei gleichzeitig übergebenem Wunsch-Attribut "id": tr:id{50-99}). Die Funktion braucht nunmehr, bei gleichem Ergebnis, nur noch ein Viertel der ursprünglichen Arbeitszeit! Wenn mehr als 200 Elemente durchsucht werden müssen, wird zudem der aktuelle Stand in der Statuszeile des Browsers angezeigt (allerdings leider nicht in jedem Browser). Möchte man einen anderen Schwellenwert für die Anzeige definieren, so kann man dies in der Routine selbst tun - der Wert wird mit var showStatus=... definiert.
Aber insbesondere bei einer Vielzahl von Elementen stellt hier ggf. das Ändern nicht der vielen Elemente (mittels toggle()), sondern des CSS selbst (mittels cssRule()) eine Alternative dar, bei der man mit einer Änderung auf einen Schlag eine Vielzahl von Elementen beeinflussen kann. Allerdings unterstützt nicht jeder DOM-Browser diese Möglichkeit (Opera erst ab Version 9).

Eine Beispiel-Tabelle mit ID-Attributen:

<table>
 <tr><th>Überschrift</th></tr>
 <tr id="Tab1A"><td>Zeile 1</td></tr>
 <tr id="Tab1B"><td>Zeile 2</td></tr>
 <tr id="Tab1C"><td>Zeile 3</td></tr>
 <tr id="Tab1D"><td>Zeile 4</td></tr>
 <tr id="Tab1E"><td>Zeile 5</td></tr>
 <tr id="Leg1"><td>Legende</td></tr>
</table>
Überschrift
Zeile 1
Zeile 2
Zeile 3
Zeile 4
Zeile 5
Legende

Der Aufruf toggle("fold","tr:id","Tab1") faltet hier alle Tabellenzeilen, bis auf die Überschriftszeile (kein Toggle-Attribut) und die Legendenzeile (Toggle-Attribut hat nicht die Basiskennung "Tab1"). Durch direkten Zugriff auf die ID (toggle("fold","Tab1B")), kann man auch gezielt einzelne Elemente bearbeiten.

Die an die Basiskennung ggf. anschließende, beliebige Restkennungen, können toggle() dann als Ausnahme übergeben werden. Diese Elemente werden entweder ignoriert (xSwitch ist false oder leer) oder komplementär bearbeitet (xSwitch ist true)! Beispiel (wegen gleicher Kennungen wird hier mit dem voreingestellten GID-Attribut gearbeitet):

<table>
 <tr><th>Überschrift</th></tr>
 <tr gid="Tab2A"><td>Zeile 1</td></tr>
 <tr gid="Tab2B"><td>Zeile 2</td></tr>
 <tr gid="Tab2B"><td>Zeile 3</td></tr>
 <tr gid="Tab2C"><td>Zeile 4</td></tr>
 <tr gid="Tab2D"><td>Zeile 5</td></tr>
 <tr gid="Leg2"><td>Legende</td></tr>
</table>
Überschrift
Zeile 1
Zeile 2
Zeile 3
Zeile 4
Zeile 5
Legende

Das "Verstecken" mit toggle("hide","tr","Tab2","A","C") ersetzt die Tabellenzeilen 2, 3 und 5 durch einen Platzhalter. Die Zeilen 1 und 4 haben zwar die korrekte Basiskennung "Tab2", aber deren Restkennungen "A" und "C" wurden explizit vom Verstecken ausgenommen.

Beim "Versteck-Switch" (gleicher Code mit zusätzlichem Parameter true) ist das Ergebnis gleich, wenn alle Elemente sichtbar waren. Wenn aber die Zeilen 1 und 4 vor dem Aufruf bereits versteckt sind (z.B. durch style="visibility:hidden;"), dann hätte der Switch-Aufruf sie angezeigt (den Effekt sieht man, wenn man die Buttons in der Reihenfolge der Ziffern nacheinander aufruft, bzw. wenn man wechselweise den "Versteck-Switch" und den "Anzeige-Switch" betätigt). Dies ermöglicht es auch, mit einem einzigen Aufruf gezielt bestimmte Inhalte darzustellen, egal ob sie vorher sichtbar waren oder nicht (jedenfalls bei geschickter Ausnutzung der Restkennungen). Stets zwei getrennte Aufrufe, einer zum Verstecken unerwünschter, ein zweiter zum Anzeigen erwünschter Elemente, würde auch die doppelte Rechenzeit benötigen - insbesondere bei großen Dateien mit vielen Elementen eine i.d.R. sinnlose Zeitverschwendung.

Anmerkung: Anstatt die Ausnahme-Restkennungen einzeln zu übergeben, kann man auch alles in einer einzigen Zeichenkette zusammenfassen! Statt toggle("hide","tr","Tab2","A","C",true) kann man also auch toggle("hide","tr","Tab2","A|C",true) schreiben.

Will man nicht Tabellen-Zeilen, sondern -Spalten bearbeiten, so muß man natürlich jede Zelle der betreffenden Spalte kennzeichnen, da HTML Tabellen-Spalten nicht kennt:

<table border="1" cellpadding="7"><tr>
 <th id="Tab3Head" colspan="2">Überschrift</th>
</tr><tr>
 <td id="Tab3BodyA1" onMouse...>Zelle A1</td>
 <td id="Tab3BodyB1" onMouse...>Zelle B1</td>
</tr><tr>
 <td id="Tab3BodyA2" onMouse...>Zelle A2</td>
 <td id="Tab3BodyB2" onMouse...>Zelle B2</td>
</tr><tr>
 <td id="Tab3BodyA3" onMouse...>Zelle A3</td>
 <td id="Tab3BodyB3" onMouse...>Zelle B3</td>
</tr><tr>
 <td id="Tab3BodyA4" onMouse...>Zelle A4</td>
 <td id="Tab3BodyB4" onMouse...>Zelle B4</td>
</tr><tr>
 <td id="Tab3BodyA5" onMouse...>Zelle A5</td>
 <td id="Tab3BodyB5" onMouse...>Zelle B5</td>
</tr><tr>
 <th id="Tab3Foot" colspan="2">Legende</th>
</tr></table>
Überschrift
Zelle A1 Zelle B1
Zelle A2 Zelle B2
Zelle A3 Zelle B3
Zelle A4 Zelle B4
Zelle A5 Zelle B5
Legende

Zuerst werden, jedenfalls wenn toggle() verfügbar ist, die einzelnen Zellen mit toggle('back trans','th:id','Tab3'); (Kopf- und Fußzelle) bzw. toggle('back trans','td:id{41-51}','Tab3'); (Inhaltszellen) vorbereitet. Da unbearbeitete Tabellen prinzipiell durchsichtig sind, wird die Hintergrundfarbe auf weiß und die Transparenz auf 50% gesetzt, was einen Milchglas-Effekt ergibt (der Tabelle selbst eine Hintergrundfarbe zuzuweisen wäre hier unsinnig, da ja nicht die Tabelle als ganzes, sondern nur einzelne Zellen mit einem Effekt versehen werden soll). Der eigentliche Toggle-Effekt wird dann gestartet, wenn man die Maus über die Inhaltszellen bewegt. Im dafür zuständigen onMouseOver sind folgende Aufrufe enthalten:

  1. toggle('trans:20 back:#FFEEEE border:#FFEEEE','td:id{41-51}','Tab3BodyA'); (aufgerufen mit über jeder linken Tabellen-Zelle) reduziert die Transparenz von den voreingestellten 50% auf 20% für die komplette Tabellen-Spalte, also allen Zellen deren ID mit TabBodyA beginnt (durch das angehängte {41-53} werden nicht alle Zellen (TD) des gesamten Dokumentes überprüft, sondern nur die Zellen Nr. 41 bis Nr. 53, jeweils inkl.). Gleichzeitig werden die Hintergrund- und die (CSS-)Rahmenfarbe dieser Spalte auf hellrot gesetzt, um auch einen Effekt auf Browsern zu erzielen, die noch keine Transparenz unterstützen.
  2. toggle('border','Tab3BodyA4'); (aufgerufen über jeder Tabellen-Zelle - natürlich mit der jeweiligen Zellen-ID) färbt den (CSS-)Zellenrand schwarz.

Analog werden entsprechende Aufrufe für die rechten Tabellen-Zellen durchgeführt, und mit onMouseOut der Zustand wieder zurückgesetzt.

Da die Interaktivität an eine Bedingung geknüpft ist (nämlich der Benutzung eines DHTML-Browsers mit JavaScript ab Version 1.5), sollten die Steuerelemente ggf. auch nur bei gegebener Funktionalität anwählbar sein. In den obigen Beispielen sind deswegen die Aufrufe/Buttons mit if(toggle("test")) { ... } (oder kürzer: if(toggle()) { ... }) geklammert (alternativ könnte man auch auf is_w3cxDOM der Systemvariablen zurückgreifen). toggle() gibt true zurück, wenn das Falten technisch möglich ist, false wenn nicht. Um Fehler zu vermeiden, falls das externe Script nicht geladen werden konnte, wurde außerdem im Kopf der HTML-Datei eine Dummy-Funktion gleichen Namens erstellt (sie gibt stets false zurück). Erst wenn das externe Script mit der eigentlichen Funktion toggle() geladen wurde, wird auch diese statt der Dummy-Funktion angesprungen und der korrekte Rückgabewert ermittelt. Wenn toggle() ausführbar ist, enthält nach regulärer Ausführung der Rückgabewert die Anzahl der tatsächlich bearbeiteten Elemente (0, falls kein passendes Element gefunden wurde).

Kleines Toggle-Beispiel
(ein größeres Beispiel wäre die GfA-Befehlsreferenz)

Liste verschiedener Betriebsssteme
Betriebssystem Hersteller Jahr OS-Basis
GEM 1.x Digital Research 1982 DOS
Linux 9 RedHat 2003 Posix
MacOS 9.x Apple 1999 Proprietär
MacOS X Apple 2002 FreeBSD
MultiTOS Atari 1993 Posix
TOS 1.x Atari 1983 CP/M68k & DOS
Windows 95 Microsoft 1995 DOS
Windows NT Microsoft 1993 Proprietär

HTML-Code

Der externe Quellcode: toggle.zip

Updates:
08.10.2005: 
Erweiterung: Proprietärer Transparenz-Code für die Browser mit KTHML-Engine (Konqueror, Safari) eingefügt.
09.06.2004: 
Korrektur: Unter bestimmten Umständen konnte der Rückgabewert (Anzahl bearbeiteter Elemente) um 1 zu niedrig ausfallen.
24.04.2004: 
Erweiterung: Es kann jetzt auch die Rahmenfarbe (border) eingestellt werden.
17.04.2004: 
Erweiterung: Es können nun auch Transparenz (trans), Farbe (color) und Hintergrundfarbe (back) eingestellt werden. Der Schwellenwert für die Fortschrittsanzeige wurde auf 200 Elemente hochgesetzt und kann jetzt leichter eigenen Vorstellungen angepaßt werden.
19.03.2004: 
Erweiterung: Bei fold/unfold kann jetzt die Darstellungsart übergeben werden, bei den Tagnamen ein Arbeitsbereich.


Kurz-URL dieses Artikels: http://Coding.binon.net/Toggle