JavaScript: Einbindung in HTML mit dem script-Element

Vorbemerkung

Von den vielen Möglichkeiten, JavaScript in HTML-Dokumente einzubetten, werden hier nur wenige gängige vorgestellt und empfohlen. Dieses Kapitel geht davon aus, dass HTML und JavaScript möglichst getrennt werden und sich JavaScripte eigenständig hinzuschalten. Die Hintergründe zu diesem Ansatz finden Sie im Kapitel Sinnvoller JavaScript-Einsatz.

Das script-Element

Zur Einbindung von JavaScript-Code in HTML-Dokument existiert in das HTML-Element script. Dieses darf sowohl im Kopf (head-Element) als auch im Körper (body-Element) eines HTML-Dokuments auftauchen. Es kann entweder direkt JavaScript-Code beinhalten, wie in diesem Beispiel:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Dokument mit integriertem JavaScript</title>
<script type="text/javascript">
window.alert("Hallo Welt!");
</script>
</head>
<body>
<h1>Dokument mit integriertem JavaScript</h1>
</body>
</html>

Oder es kann leer sein und auf eine externe Datei mit JavaScript-Code verweisen. Diese Nutzungsweise sollten Sie vorziehen und Ihre JavaScripte möglichst in separate Dateien auslagern.

Schreiben sie dazu Ihren JavaScript-Code in eine eigene Datei und speichern Sie sie mit der Dateiendung .js ab. Notieren Sie im Dokumentkopf ein script-Element, das den Browser auf die externe JavaScript-Datei hinweist. Dazu notieren Sie im src-Attribut die Adresse (URI), unter der das Script abrufbar ist. Vergessen Sie auch nicht das Attribut type mit dem festen Wert text/javascript. Dieses teilt dem Browser unmissverständlich mit, dass sie es sich bei ihrem Code um JavaScript handelt.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Dokument mit externem JavaScript</title>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<h1>Dokument mit externem JavaScript</h1>
</body>
</html>

In der Datei script.js können Sie nun JavaScript-Anweisungen, Funktionen, Objekte und so weiter notieren. Selbstverständlich können Sie mit dieser Methode mehrere Scripte einbinden: Verwenden Sie dazu einfach mehrere script-Elemente.

Beachten Sie, dass diese eingebundenen Dateien direkt JavaScript-Code enthalten müssen. HTML-Code darf darin nicht vorkommen – in JavaScript-Strings ist er natürlich noch erlaubt. Insbesondere ist es nicht nötig, den JavaScript-Code in der separaten Datei noch einmal in ein script-Element zu verpacken. Dies würde dazu führen, dass der Browser den JavaScript-Code nicht korrekt ausführt.

Ihre Scriptdateien können Sie – genauso wie Stylesheets, Grafiken usw. – auch in Unterverzeichnissen und sogar auf anderen Webservern unterbringen. Solange die angegebene URI korrekt ist, wird ein JavaScript-fähiger Browser sie beim Anzeigen des Dokuments herunterladen und ausführen.

Ausführung von script-Elementen

Mit dem script-Element können Sie sowohl Scripte im Dokumentkopf als auch im Dokumentkörper einbetten. Die Ausführung des Scriptcodes läuft nach gewissen Regeln ab, die wir im folgenden betrachten.

Wenn der Browser das HTML-Dokument vom Webserver empfängt, beginnt er sofort damit, den Quellcode zu verarbeiten und in eine interne Speicherstruktur, das Document Object Model (DOM) zu überführen. Das dafür zuständige Modul im Browser nennt sich Parser und der Verarbeitungsvorgang Parsen.

Sobald der Parser auf ein script-Element trifft, wird das Parsing des HTML-Dokuments angehalten und der JavaScript-Code innerhalb des script-Elements ausgeführt. Dasselbe gilt für externe JavaScript-Dateien: Der HTML-Parser stoppt, lädt die externe JavaScript-Datei vom Webserver, führt den JavaScript-Code aus und fährt erst dann mit der Verarbeitung des restlichen HTML-Quellcodes fort.

Diese Vorgehensweise, den JavaScript-Code direkt beim Einlesen des HTML-Dokuments auszuführen, hat folgende Konsequenzen:

Scripte haben Zugriff auf die Objekte vorher eingebundener Scripte

Die script-Elemente samt enthaltenem JavaScript-Code bzw. aus externen Dateien eingebundener JavaScript-Code werden in der Reihenfolge ausgeführt, in der sie im HTML-Quelltext notiert sind. Wenn Sie verschiedene Scripte haben, die aufeinander aufbauen, so müssen Sie sie nacheinander einbinden.

<script type="text/javascript" src="grundlagenscript.js"></script>
<script type="text/javascript" src="aufbauscript.js"></script>
<script type="text/javascript">
// Anwendung der Scripte
helferfunktion();
</script>

Das Beispiel bindet drei Scripte ein, die ersten beiden als externe Dateien, das dritte direkt im HTML-Code. Da der Browser die Scripte in der Reihenfolge ihrer Einbindung ausführt, können spätere Scripte die Objekte, Funktionen und Variablen nutzen, die die vorher eingebundenen Scripte definiert haben. Im Beispiel wird zuerst grundlagenscript.js eingebunden, heruntergeladen und ausgeführt. Das darauffolgende Script aus der Datei aufbauscript.js kann die darin notierten Funktionen nutzen. Schließlich kann das dritte Script eine Funktion nutzen, die in aufbauscript.js definiert wurde.

Externe Scripte verzögern den Aufbau des Dokuments

Dass der Webbrowser die eingebundenen Scripte nicht erst nach, sondern bereits während dem Einlesen des HTML-Codes ausführt, hat Vor- und Nachteile. Einerseits werden Scripte so schnell wie möglich ausgeführt und es ist garantiert, dass ein externes Script ausgeführt wird, bevor ein nachfolgendes internes Script abgearbeitet wird. Andererseits verlangsamt sich der Seitenaufbau, wenn große externe Scriptdateien vom Webserver heruntergeladen werden.

Dieser Nachteil kann dadurch umgangen werden, alle script-Elemente in der notwendigen Reihenfolge am Dokument-Ende zu platzieren anstatt wie üblich in den Dokumentkopf. Aus Gründen der kürzeren Ladezeit und des schnelleren Aufbau des Dokumentes wird dies immer öfter empfohlen. Es setzt allerdings eine bestimmte Arbeitsweise voraus. Im Abschnitt Ereignisbasierte Scripte werden wir eine Methode kennenlernen, bei die Scripte die Hauptarbeit erst verrichten, wenn das Dokument vollständig geladen wurde.

Scripte können während des Ladens das Dokument mit document.write ergänzen

Mit der Methode document.write kann ein Script schon während dem Laden das Dokument direkt beeinflussen und einige Weichen stellen. document.write nimmt HTML-Code in einem JavaScript-String entgegen und fügt diesen an der Stelle ins Dokument ein, an denen das zugehörige script-Element steht.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Zugriff auf das DOM während dem Parsen des Dokuments</title>
<script type="text/javascript">
document.write("<link rel='stylesheet' href='javascript.css'>");
</script>
</head>
<body>
<script type="text/javascript">
document.write("<p><a href='javascript:location.reload()'>" +
	"Seite mittels JavaScript neu laden<\/a><\/p>");
</script>
</body>
</html>

Das Beispiel enthält zwei Scripte mit document.write-Aufrufen. Diese schreiben HTML-Elemente ins Dokument, einmal ein Verweis auf ein Stylesheet und einmal ein Textabsatz mit einem JavaScript-Link.

document.write ist beim »Unobtrusive JavaScript« nur sehr selten sinnvoll. Inhalte, die nur bei aktiviertem JavaScript sichtbar sein sollen, da sie auf JavaScript-Funktionalität beruhen, sollten Sie ohne document.write dynamisch ins Dokument einfügen. Die dazu nötigen Techniken werden wir noch kennenlernen.

Der Anwendungsbereich von document.write wird oftmals missverstanden. Wir haben hier den einen von zwei möglichen Anwendungsfällen kennenlernt: Das Ergänzen eines Dokuments noch während der Browser den HTML-Code einliest. Wenn document.write jedoch nach dem vollständigen Einlesen de HTML-Codes aufgerufen wird, hat die Methode einen ganz anderen Effekt und eignet sich nicht dazu, das vorhandene Dokument via JavaScript zu ändern.

Ein Script hat Zugriff auf die Elemente vor dem zugehörigen script-Element

Wie Sie vielleicht wissen, ist die häufigste Aufgabe von JavaScripten der Zugriff auf das Dokument über die DOM-Schnittstelle, die die Elemente und deren Textinhalte als Knotenobjekte zugänglich macht. Da ein Script mitten im Parsing-Prozess, also während des Einlesens des HTML-Dokuments ausgeführt wird, hat es zu diesem Zeitpunkt noch nicht Zugriff auf den gesamten DOM-Elementenbaum. Stattdessen kann es nur auf einen Teil-Baum zugreifen, nämlich auf die Elemente, die vor dem zugehörigen script-Element liegen und somit vom Parser bereits verarbeitet wurden.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Zugriff auf das DOM während dem Parsen des Dokuments</title>
<script type="text/javascript">
// Der Titel ist an dieser Stelle bereits verfügbar:
window.alert( document.title );
// Der Dokumentkörper allerdings noch nicht (ergibt null):
window.alert( document.body );
// Die Überschrift ebensowenig (ergibt null):
window.alert( document.getElementById("überschrift") );
</script>
</head>
<body>

<script type="text/javascript">
window.alert( document.title ); // OK
// Der Dokumentkörper ist erst an dieser Stelle verfügbar:
window.alert( document.body );
// Die Überschrift allerdings noch nicht (ergibt null):
window.alert( document.getElementById("überschrift") );
</script>

<h1 id="überschrift">Beispielüberschrift</h1>
<script type="text/javascript">
window.alert( document.title ); // OK
window.alert( document.body ); // OK
// Die Überschrift ist erst an dieser Stelle verfügbar:
window.alert( document.getElementById("überschrift") );
</script>

</body>
</html>

Das Beispiel enthält drei Scripte, die jeweils versuchen, auf den Dokument-Titel (title-Element), den Dokument-Körper (body-Element) und eine Überschrift (h1-Element) zuzugreifen. Je nachdem, an welcher Stelle sich das Script und das angesprochene Element befinden, ist der Zugriff auf das Element möglich oder nicht. Der Zugriff funktioniert erst dann, wenn das anzusprechende Element dem jeweiligen Script vorangeht und bereits geparst wurde. Das Element muss dazu noch nicht abgeschlossen sein. Im Beispiel kann ein Script im body-Element bereits auf das geöffnete, aber noch nicht geschlossene body-Element zugreifen. Das Script hat jedoch nur Zugriff auf die vorherigen Geschwisterelemente (im Beispiel das h1-Element).

Dies heißt nun nicht, dass sie zwangsläufig all ihre Scripte ans Dokumentende setzen müssen, damit ihr Script auf das gesamte Dokument zugreifen kann. Dieser Sachverhalt soll Ihnen nur die Ausgangssituation für ereignisbasierte Scripte schildern, die automatisch ihre Arbeit aufnehmen, sobald der gesamte HTML-Code geparst wurde und das Dokument fertig geladen ist.

Das noscript-Element

Das noscript ist als Gegenstück zu script gedacht: Damit lassen sich Alternativinhalte für Programme ins Dokument einfügen, die keine Scripte unterstützen. Browser, in denen JavaScripte deaktiviert oder nicht verfügbar ist, zeigen den Alternativinhalt an. Der Inhalt richtet sich auch an Programme wie Suchmaschinen-Robots, die das Dokument automatisiert verarbeiten, ohne die Scripte dabei zu beachten.

<noscript>
   <p>Dieser Absatz ist gehört zum Inhalt des Dokuments, ist aber
   im Browser nur zu sehen, wenn JavaScript deaktiviert oder nicht
   zur Verfügung steht.</p>
</noscript>

Der Sinn von noscript ist, die Informationen zugänglich zu machen, die sonst nur mithilfe des Scriptes zugänglich wären oder sogar durch das Script eingefügt werden. Diese Abwärtskompatibilität einer Website und die Zugänglichkeit aller Inhalte ohne JavaScript ist zwar erstrebenswert, allerdings zäumt »Unobtrusive JavaScript« das Pferd von vorne anstatt von hinten auf: Alle Informationen liegen bereits im Dokument und es ist auch ohne JavaScript gut bedienbar. Mittels JavaScript werden dann Zusatzfunktionen eingebaut, die die Bedienung und das Lesen der Inhalte vereinfachen und verbessern.

Im Unobtrusive JavaScript kommt dem noscript-Element daher keine Bedeutung zu. Von seiner Verwendung wird sogar abgeraten, da es dazu verleitet, JavaScript-Logik mit dem HTML-Code fest zu verschweißen, anstatt diese sauber zu trennen. Gestalten Sie Ihre Website so, dass ohne JavaScript möglichst alle Inhalte zugänglich sind und alle Funktionen zur Verfügung stehen. Ihre JavaScripte schalten sich dann hinzu und modifizieren das Dokument entsprechend. Anstatt also mittels noscript ein Element einzufügen, das nur ohne JavaScript relevant ist, sollten Sie dieses ganz normal ohne noscript im Dokument notieren. Falls es bei aktiviertem JavaScript nicht benötigt wird, dann können Sie es mittels JavaScript verändern oder ganz ausblenden.

Aus den besagten Gründen wird an dieser Stelle nicht näher auf noscript eingegangen – in den meisten Fällen werden Sie noscript nicht brauchen. Es gibt nur einige Spezialfälle, in denen noscript angemessen ist: Etwa wenn es sich bei der Website um eine reine JavaScript-Webanwendung handelt, die (noch) keine Alternativversion anbietet. Dann können Sie mit noscript einen Hinweis darauf hinterlegen, dass die Site einen JavaScript-fähigen Browser zwingend voraussetzt.