JavaScript - Tutorial - Anhang E - Kompatibilität

Trotz der Standardisierung der JavaScript-Sprache gibt es teilweise größere Unterschiede bei der Interpretation solcher Scripte zwischen den Browsern, teilweise sogar zwischen verschiedenen Versionen gleicher Herkunft (beispielsweise zwischen Netscape4 und Netscape6).
Um alle Eventualitäten abzuchecken, habe ich alle Skripte dieses Tutorials mit den jeweils gängigen Versionen von Netscape Navigator (4 bis 7) / Mozilla, Konqueror 2 und 3, Opera 5 bis 7 und MS Internet Explorer 5 und 6 getestet, und zwar mit wechselndem Erfolg.
Teilweise muß man schon größere Kniffe und Tricks anwenden, um ein Script an all diesen Browsern zum Laufen zu überreden. Einige dieser Tricks sollen hier erläutert werden.

Zeitgeber und Zeitschleifen
Layer und div-Sektionen
Ereignisauswertung (speziell: Maus)


Zeitgeber und Zeitschleifen


Bekanntermaßen läßt sich mit window.setInterval und window.setTimeout ein Befehl zeitgesteuert ausführen. Allerdings ist diese Zeitsteuerung nicht allzu präzise, für Netzpräsentationen jedoch völlig ausreichend.
Die Funktion window.setInterval sorgt dabei für eine immer wiederkehrende, zeitlich unbegrenzte zyklische Ausführung einer bestimmten Aktion mit zwischengeschalteten Wartepausen, window.setTimeout veranlasst die einmalige Ausführung einer Aktion nach einer vorgegebenen Wartepause.
Beide Varianten lassen sich abbrechen, und zwar mittels window.clearInterval beziehungsweise window.clearTimeout. An diese Funktionen muß der Rückgabewert der jeweiligen window.setInterval- bzw. window.setTimeout- Funktion, mit der der Vorgang gestartet wurde, als Parameter übergeben werden.
Damit scheint klar, welche Funktion man für endlose Animationen, Laufschriften oder ähnliches verwenden sollte: und zwar window.setInterval.
Aber Vorsicht: ist nicht cool, man. Ganz im Gegenteil. Ursprünglich habe ich diese Funktion für meine Animationen verwendet, was regelmäßig zur Unansprechbarkeit des Systems geführt hat.
Dies ist darin begründet, daß so mancher Browser bei längeren und aufwendigeren Aktionen nicht auf deren Abschluß wartet, sondern frisch und fröhlich die nächste Aktion dieser Sorte nach Ablauf des Timers startet, während die vorige Aktion noch läuft. Dies kann den Computer schon mal bis zum Stillstand verlangsamen, vor allem ältere Rechner wie meine 166-MHz-Büchse.
Man kann sich allerdings durch einen immer wiederkehrenden Aufruf von window.setTimeout aus der zyklisch auszuführenden Funktion heraus Abhilfe verschaffen. Das kann so aussehen:
function MyTimer()
{
  ...
  ...
  window.setTimeout("MyTimer()",...);
}
Zum Start der Zeitschleife ruft man dann nur einmal window.setTimeout("MyTimer()",...); oder MyTimer() auf, und schon ist der Prozess am Werkeln, da MyTimer nach Abschluß all seiner Aufgaben immer wieder einen Timer auf sich selber setzt.
Wichtig zur Vermeidung des oben beschriebenen Effekts ist hier, daß der neue Timer wirklich erst nach Abarbeitung aller Aufgaben gesetzt wird.

Ein weiteres Problem tut sich jedoch an dieser Stelle auf: der Konqueror kann immer nur einen Zeitgeber zur gleichen Zeit bearbeiten (Stand 2002). Wird an diesem Browser ein neuer Zeitgeber gestartet, wird ein eventuell bereits aktivierter Zeitgeber abgebrochen und kommt nicht zur Ausführung. Im Prinzip ist auch das kein Problem, man muß sich nur danach richten.
Man sollte also immer nur einen Zeitgeber auf seinen Seiten einbinden, der dann alle Aufgaben ausführt.
In meinen Animationen zeige ich, wie man mehrere unterschiedliche Aufgaben in einem Zeitgeber zusammenfaßt.

Layer und div-Sektionen


Layer im herkömmlichen Sinne (<layer>-tag) haben in HTML nichts zu suchen und gehören zu keinem Standard. Daher haben sie auch in JavaScript nichts zu suchen.
Im Volksmund werden aber auch absolut positionierte <div>-Sektionen "Layer" genannt und gerne von ambitionierten JavaScript-Programmierern über Dokumente geschoben, eingeblendet, ausgeblendet, vergrößert, verkleinert und was weiß ich noch alles, daß einem dabei ganz schwindelig wird.
Leider ist der Umgang mit solchen Objekten an den verschiedenen Browsern recht unterschiedlich.
Am Netscape4 befinden sich die zu den <div>-Sektionen gehörigen JavaScript-Objekte in der Hierarchie im Objekt window.document.
Am MS Internet Explorer, Konqueror und Opera findet man diese in window.document.all, wobei die meisten nützlichen Variablen im Unterobjekt style gesammelt sind.
Im Netscape6 sind diese Objekte nach W3C-DOM in die Hierarchie eingebunden, man kann beispielsweise die Funktion window.document.getElementById(...) nach den einzelnen Objekten fragen, wobei sich auch hier die meisten nützlichen Variablen im Unterobjekt style und nicht mehr wie bei Netscape4 direkt im zugehörigen Objekt befinden.
Es gibt also an jedem Browser eine Lösung, und zwar an fast jedem eine andere.
Dies kann man jedoch in einer Funktion zusammenfassen, die etwa so aussehen könnte:
function GetDivStyle(Div_ID)
{
/* MSIE, Konqueror, Opera : */
  if (window.document.all)
    return eval("window.document.all."+Div_ID+".style");

/* Netscape6/Mozilla : */
  if (typeof(window.document.getElementById)=="function")
    return window.document.getElementById(Div_ID).style;

/* uebrig bleibt Netscape4 : */
  return eval("window.document."+Div_ID);
}
Diese Funktion gibt an allen genannten Browsern genau das Objekt zurück, was die CSS-Styles enthält, die zur Div-Sektion mit dem ID-Namen Div_ID (Eingabeparameter) gehören. Über die Manipulation der Eigenschaften dieses Objekts kann man es verschieben, die Größe ändern, es verbergen, die Anzeigereihenfolge ändern und vieles mehr.

Einen Wermutstropfen gibt es noch: Der Konqueror 2 kennt die Eigenschaft visibility nicht (Stand 2002). Will man also einen solchen Layer verbergen, muß man ihn über den linken oder oberen Dokumentrand genügend weit hinausschieben (Attribute left oder top auf negative Werte setzen). Aber auch das ist kein Problem, man muß sich nur danach richten.

In diesem Tutorial gibt es einige Beispiele zu diesem Thema:
Beispiel 1
Beispiel 2

Ereignisauswertung (speziell: Maus)


Auch dafür existiert an jedem Browser eine Lösung, und auch hier für jeden eine andere.
Das fängt schon damit an, daß man die Objektüberwachung an jedem Browser anders auslöst. Ich liste am besten gleich mal ein Beispiel für die Überwachung von Mausbewegungen auf:

...
<script type="text/javascript"><!--
...

function MouseMove(event)
/* Ueberwachung der Mausbewegungen */
{
  var mausx,mausy;

/* MSIE, Konqueror, Opera : */
  if (document.all)
  {
    mausx=event.clientX;
    mausy=event.clientY;
    if (document.body.scrollLeft)
      mausx+=document.body.scrollLeft;
    if (document.body.scrollTop)
      mausy+=document.body.scrollTop;
  }

/* Netscape, Mozilla : */
  else
  {
    mausx=event.pageX;
    mausy=event.pageY;
  }

/* Auswertung : */
  ...
  ...
}


/* Initialisierung der Mausueberwachung */
function MouseInit()
{
/* MSIE, Konqueror, Opera : */
  if (document.all)
    window.onmousemove=MouseMove;

/* Netscape, Mozilla : */
  else
  {

/* Netscape6, Mozilla : */
    if (typeof(document.addEventListener)=="function")
      document.addEventListener("mousemove",MouseMove,true);

/* Netscape4 : */
    else
    {
      window.captureEvents(Event.MOUSEMOVE);
      window.onmousemove=MouseMove;
    }
  }
}

...
//--></script>
...

<!-- onLoad="MouseInit();" veranlasst Netscape zur Ereignisbehandlung,
     onMouseMove="MouseMove(event);" tut das im MSIE: -->
<body ... onLoad="MouseInit();" onMouseMove="MouseMove(event);" ...>

...
Während sich MSIE, Konqueror und Opera mit onMouseMove="..." als Anweisung zur Ereignisüberwachung zufrieden geben, will Mozilla/Netscape6 mit document.addEventListener(...) gebeten werden, während Netscape4 sich mit window.captureEvents(Event....); window.onmousemove=...; bitten läßt.
Auch die Mauskoordinaten heißen im event-Objekt verschieden:
Netscape, Mozilla: event.pageX, event.pageY;
MSIE, Konqueror, Opera: event.clientX, event.clientY.
Bei Netscape und Mozilla sind die scroll-Werte der Rollbalken bereits enthalten. In MSIE, Konqueror und Opera muß man sie extra dazuaddieren.
Beispiel

Autor: Ulrich Kritzner