JavaScript: Einbindung in HTML mit dem script-Element

Vorbemerkung

Es gibt viele Möglichkeiten, JavaScript in HTML-Dokumente einzubetten. In dieser Einführung werden 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 ein HTML-Dokument existiert 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>
<html>
<head>
<title>Dokument mit integriertem JavaScript</title>
</head>
<body>
<h1>Dokument mit integriertem JavaScript</h1>
<script>
window.alert("Hallo Welt!");
</script>
</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 am Dokument-Ende ein script-Element, das den Browser auf die externe JavaScript-Datei hinweist. Dazu notieren Sie im src-Attribut die Adresse (URL), unter der das Script abrufbar ist.

<!DOCTYPE html>
<html>
<head>
<title>Dokument mit externem JavaScript</title>
</head>
<body>
<h1>Dokument mit externem JavaScript</h1>
<script src="script.js"></script>
</body>
</html>

In der Datei script.js können Sie nun JavaScript-Anweisungen, Funktionen, Objekte und so weiter notieren. Schreiben Sie zum Test einmal folgende Anweisung in die JavaScript-Datei:

window.alert('Hallo Welt!');

Sie können mit dieser Methode auch mehrere Scripte einbinden. Platzieren Sie dazu mehrere script-Elemente untereinander.

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 Script-Dateien können Sie – genauso wie Stylesheets, Grafiken usw. – auch in Unterverzeichnissen und sogar auf anderen Webservern unterbringen. Solange die angegebene URL 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 <head>…</head> als auch im Dokumentkörper <body>…</body> einbetten. Die Ausführung des Scriptcodes läuft nach gewissen Regeln ab, die wir im Folgenden betrachten.

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

Sobald der Parser auf ein script-Element trifft, wird das Parsen des HTML-Dokuments angehalten und der JavaScript-Code innerhalb des script-Elements ausgeführt. Das gilt auch 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-Quelltextes fort.

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

Scripte haben Zugriff auf die Objekte vorher eingebundener Scripte

Der JavaScript-Code in script-Elementen bzw. der externe Script-Code wird in der Reihenfolge ausgeführt, in der die script-Elemente im HTML-Quelltext notiert sind. Wenn Sie verschiedene Scripte haben, die aufeinander aufbauen, so müssen Sie sie nacheinander einbinden.

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

Das Beispiel bindet drei Scripte ein, die ersten beiden als externe Dateien, das dritte direkt im HTML-Code. Der Browser führt die Scripte in der Reihenfolge ihrer Einbindung aus. Daher 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 Browser die eingebundenen Scripte nicht erst nach, sondern bereits während des Einlesens 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.

Es ist daher empfehlenswert, alle script-Elemente in der notwendigen Reihenfolge am Dokument-Ende zu platzieren. Dadurch wird der Aufbau des Dokumentes nicht durch das Herunterladen und Ausführen von JavaScript unterbrochen.

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 des Ladens das Dokument direkt beeinflussen und einige Weichen stellen. document.write nimmt HTML-Code als String entgegen. Es fügt den HTML-Code an der Stelle ins Dokument ein, an der das zugehörige script-Element steht.

<!DOCTYPE html>
<html>
<head>
<title>Zugriff auf das DOM während dem Parsen des Dokuments</title>
<script>
document.write("<link rel='stylesheet' href='stylesheet.css'>");
</script>
</head>
<body>
<script>
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 selten sinnvoll. Es gibt zwar Inhalte, die nur bei verfügbarem JavaScript sichtbar sein sollen, da sie auf JavaScript-Funktionalität beruhen. Im Beispiel ist das ein Link, der die Seite mittels JavaScript neu lädt. Allerdings sollten Sie solche Inhalte ohne document.write dynamisch ins Dokument einfügen. Die dazu nötigen Techniken werden wir noch kennenlernen.

document.write hat zwei möglichen Anwendungsfälle, von denen wir einen kennenlernt haben: Das Ergänzen eines Dokuments während der Browser den HTML-Code einliest. Wenn document.write jedoch nach dem Einlesen des HTML-Codes aufgerufen wird, hat die Methode einen ganz anderen Effekt: Sie überschreibt den gesamten Inhalt des Dokuments. Sie eignet sich also nicht dazu, das vorhandene Dokument gezielt via JavaScript zu ändern.

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

Die häufigste Aufgabe von JavaScripten ist der Zugriff auf das Dokument über die DOM-Schnittstelle. Diese macht die Elemente und deren Textinhalte als Knotenobjekte zugänglich.

Ein Script wird wie gesagt während des Einlesens des HTML-Dokuments ausgeführt. Zu diesem Zeitpunkt hat es noch keinen Zugriff auf den gesamten DOM-Elementbaum. Stattdessen kann es nur auf einen Teil-Baum zugreifen, nämlich auf die Elemente, die vor dem zugehörigen script-Element liegen und somit bereits eingelesen wurden.

<!DOCTYPE html>
<html>
<head>
<title>Zugriff auf das DOM während dem Parsen des Dokuments</title>
<script>
// 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>
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>
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 gesuchte Element dem jeweiligen Script vorangeht und bereits eingelesen 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 zudem Zugriff auf die vorherigen Geschwisterelemente (im Beispiel das h1-Element), nicht jedoch auf die folgenden.

Vielleicht verstehen Sie nun, warum wir externe Scripte ans Dokument-Ende setzen haben: Sie haben dadurch Zugriff auf das gesamte Dokument.

Asynchrone Script einbinden

Das noscript-Element

Das noscript-Element 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 diese Vorgehensweise das Pferd von hinten auf.

Unobtrusive JavaScript empfiehlt eine andere Vorgehensweise: Alle Informationen liegen bereits im Dokument. Es ist daher ohne JavaScript gut bedienbar. Mittels JavaScript werden 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. Denn es verleitet dazu, 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 Inhalte einzufügen, die nur ohne JavaScript relevant ist, sollten Sie diese ganz normal ohne noscript im Dokument notieren. Falls der Inhalt bei aktiviertem JavaScript nicht benötigt wird, dann können Sie es mittels JavaScript verändern oder ganz ausblenden.

In den meisten Fällen werden Sie noscript also nicht brauchen. Es gibt einige Sonderfä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 Website einen JavaScript-fähigen Browser zwingend voraussetzt.