Beschreibung

Diese Anleitung zeigt, wie man mit CSS2, PHP und etwas JavaScript trotz validem XHTML 1.0 strict (oder XHTML 1.1) Links in einem neuen Fenster öffnen lassen kann.
Es wird gezeigt, wie man externe Links als solche mit einer Symbolgrafik kennzeichnen kann, wie man mit JavaScript das target-Attribut modifiziert, wie man dem Benutzer über eine Checkbox auswählen lassen kann, ob externe Links in einem neuen Tab/Fenster geöffnet werden sollen oder nicht und wie man diese Einstellung mit JavaScript und PHP in allen internen Unterseiten beibehält.
Beispiel: So sieht's aus

Hintergründe

Über das Pro und Contra, Links mit dem Attribut target="_blank" in einem neuen Tab/Fenster zu öffnen, wurden schon viele Glaubenskriege zwischen Befürwortern und Gegnern geführt.
Die einen fühlen sich durch Links, welche sich in einem neuen Tab/Fenster öffnen, bevormundet, die anderen wiederum finden es superpraktisch und erwarten bei externen Links gar nichts anderes.
Kurz: wie man es macht - man macht es falsch.

Da ist das Naheliegenste doch einfach, den Benutzer selbst entscheiden zu lassen. Dieser Codeschnipsel zeigt, wie das funktionieren kann.

Valide oder nicht

Mit dem Attribut target="_blank" lassen sich Links in XHTML 1.0 in der transitional-Variante in einem neuem Tab (Firefox, Opera) bzw. einem neuen Fenster (Internet Explorer < IE7) öffnen.
Bei XHTML 1.0 in der strict-Variante oder bei XHTML 1.1 ist dies jedoch nicht vorgesehen.

Hier ist das Target-Attribut vom W3C aus dem Standard gestrichen worden.
Und somit ist
<a href="www.irgendwohin.de" traget="_blank">Irgendwohin</a>
kein standardkonformes und valides XHTML. Punkt.

So bleibt als einzigste Möglichkeit, Links nicht im selben Tab/Fenster zu öffnen, die :target-Pseudoklasse des neuen CSS3.
Da sich CSS3 zur Zeitpunkt der Erstellung dieser Anleitung aber noch in der Entstehungsphase befindet und von kaum einem Browser korrekt interpretiert wird, wird hier eine Alternative aufgezeigt, die das target-Attribut zwar trotzdem verwendet, aber dank etwas JavaScript-Trickserei dennoch als scheinbar valides XHTML strict erscheint.

Der Nachteil dieser Methode ist somit, dass sie nur bei aktiviertem JavaScript funktioniert. Wenn JavaScript nicht zur Verfügung steht, werden die Links ganz normal im aktuellen Tab/Fenster geöffnet.

Vorbereitung: Markieren externer Links

Zunächst sollten alle externen Links für die Besucher der Website als solche erkenntlich gemacht werden.
Dazu werden diese Links mit einem Symbolbild versehen.
Erst mal ist also Zeichenunterricht angesagt. In einem Malprogramm nach Wahl (Paint wäre hier beispielsweise völlig ausreichend) erstelle man eine Symbolgrafik mit ca. 16x16 Pixeln. Wichtig ist, dass die Höhe der Grafik in etwa der Zeilenhöhe normalen Textes entspricht.
Diese Grafik brauchen wir ggf. in mehreren Varianten: für jeden Linkzustand (besucht, hover, usw.) eine.

Nun bedienen wir uns eines kleinen CSS-Tricks: alle Varianten der Symbolgrafik werden untereinander in einer Bilddatei angeordnet. Das spart Ladezeiten beim Seitenaufbau, da nur eine Verbindung zum Server für alle Symbolbildchen benötigt wird.
Mit CSS gelangen wir später über die Positionsangabe des Hintergrunds an das passende Symbol.
So etwa sollte die Grafik nun aussehen:
Symbolgrafik für externe Links
Zwischen den Symbolen wird etwas Abstand gelassen um Darstellungsprobleme mit verschiedenen Browsern zu umgehen.

Als nächstes werden alle Links zu externen Seiten mit einer CSS-Klasse "extlink" markiert.
Aus <a href="http://google.com">Google</a> wird somit
<a class="extlink" href="http://google.com">Google</a>

Und im Stylesheet wird eingetragen:
CSS-Code:
"../images/extlink.png" muss natürlich durch den passenden Pfad und Dateinamen der Bilddatei ersetzt werden.

Links der Klasse "extlink" sollten nun so aussehen: Google

Falls nicht, muss man etwas mit der Position des Hintergrunds ("-100px") in
background: url('../images/extlink.png') no-repeat 100% -100px; experimentieren.

JavaScript-Funktion um target-Attribut zu ändern

Im Header der XHTML-Datei wird nun eine JavaScript-Datei eingebunden:
<head>
<script src="../../include/linkopener.js" type="text/javascript"></script>
</head>

In dieser Datei wird eine JS-Funktion "linkopener" definiert:
JavaScript-Code:

Aus dem body-Tag der Seite wird die Funktion aufgerufen:
PHP-Code:
Jetzt fehlt nur noch eine Checkbox, mit welcher der Benutzer einstellen kann, ob Links zu externen Seiten in einem neuen Tab/Fenster geöffnet werden sollen oder nicht.

Da das ganze Heckmeck sowieso nur funktioniert, wenn JavaScript aktiviert ist, wird genau dieses verwendet um die Checkbox in die Seite "reinzuschreiben".
Somit vermeidet man, dass bei deaktiviertem JavaScript eine funktions- und nutzlose Checkbox in der Gegend rumsteht.

Also die Stelle, wo die Checkbox erscheinen soll (vorzugsweise im Dokument links, ganz oben oder unten) folgendes JavaScript einfügen:
JavaScript/PHP-Code:

Funktionsweise

Da in XHTML 1.0 strict oder XHTML 1.1, wie eingangs beschrieben, Links mit target-Attribut nicht erlaubt sind, wäre <a class="extlink" href="http:\\google.com" target="_blank">Google</a> nicht valide.

Die Lösung: wir machen es trotzdem! Aber so, dass es niemand merkt...

Tatsächlich werden target-Attribute auch in XHTML 1.0 strict bzw. XHTML 1.1 von jedem Browser korrekt und ohne Nebenwirkungen interpretiert.
Der Trick bei der Sache liegt darin, das unerlaubte target-Attribut erst während der Ausführung der Seite auf dem Gastrechner dynamisch mit JavaScript dazuzuschreiben.
Rein formal betrachtet erzeugt man so trotzdem ungültiges XHTML. Da es aber mit JavaScript erst zur Laufzeit geschieht, bemerkt davon kein Validator etwas.

Zugegeben: das ist ziemlich schmutzige Trickserei und viele Validator-Fundamentalisten würden dies schon aus Prinzip ablehnen.
Bevor wir uns aber in den bereits eingangs erwähnten Glaubenskriegen verzetteln sei darauf hingewiesen:
mit den derzeitigen Browsern gibt es keine "schönere" Alternative für diese Problemstellung.
Letztlich ist es ein Kompromiss zwischen XHTML-Standard und Benutzerfreundlichkeit.
Und wie eingangs ebenfalls schon angemerkt: man kann es nicht immer allen rechtmachen.

Doch nun zurück zur Funktionsweise:
Beim Laden der Seite wird aus dem body-Tag die JavaScript-Funktion "linkopener" aufgerufen.
Eine if-else-Anweisung mit PHP ruft die linkopener-Funktion mit false auf, wenn die $_GET-Variable 'ext' definiert ist. Andernfalls mit true.

Hinweis: $_GET['ext'] ist dann definiert, wenn die aktuelle Seite mit ext=0 aufgerufen wurde.
Also z.B. http://blablabla.bla/ordner/datei.php?param1=1&param2=2&ext=0&param3=3
Dabei spielt es keine Rolle, ob ext gleich 0 ist oder irgendein anderer Wert. Nur weil man nie etwas uninitialisiert belassen sollte wird hier eben ext=0 verwendet.

Die linkopener-Funktion geht alle Links der Seite durch. Gehört ein Link der Klasse "extlink" an, so werden alle target-Attribute auf target="_blank" gesetzt, wenn die Funktion mit true aufgerufen wurde, oder auf target="_self", wenn die Funktion mit false aufgerufen wurde.
Bei Links, welche NICHT der "extlink"-Klasse angehören, wird es etwas komplizierter.
Zunächst werden alle Vorkommen von "&ext=0" und "?ext=0" aus der URL entfernt.
Falls externe Links in einem neuen Tab/Fenster geöffnet werden sollen (linkopener wurde mit true aufgerufen), was's das auch schon.
Andernfalls wird ermittelt, ob in der URL ein query string vorkommt. Dies bedeutet, dass der Seite irgendwelche Variablen zugewiesen werden.
Ist dem so, dann soll diese Variablenliste mit "&ext=0" erweitert werden. Falls nicht, wird eine Variablenliste mit "?ext=0" eröffnet.
Und schließlich, wird überprüft, ob in der URL ein Anker (z.B. "#top") vorkommt.
Falls ja, so wird "&ext=0", bzw. "?ext=0" an der korrekten Position VOR dem Anker eingefügt.
Andernfalls kann es einfach an die URL angehängt werden.

Keine Panik: das klingt nur komplizierter als es ist. Wer mit der Thematik nicht ganz konform ist, kann sich in der Wikipedia über den Aufbau einer URL informieren.

Durch das Erweitern der URLs aller internen Links um &ext=0, bzw. ?ext=0, kann nun so die Einstellung (true/false) in allen verlinkten internen Seiten durch Auslesen der Varaiblenliste übernommen werden.

Und schließlich gibt es noch die Checkbox, mit der Benutzer (ab)wählen kann, ob Links zu externen Seiten denn nun bitteschön in einem neuen Tab/Fenster geöffnet werden sollen, oder ob er das blöd findet und das gefälligst unterbleiben soll.

Bei Klick auf die Checkbox wird wieder die linkopener-Funktion aufgerufen. Mit true, wenn die Checkbox angekreuzt wurde - mit false, wenn das Häkchen entfernt wurde.

Mal ein Beispiel:
Falls der Benutzer das Checkbox-Häkchen entfernt, setzt linkopener die target-Attribute aller Links der Klasse "extlink" wieder auf target="_self" und hängt an alle internen Links den Zusatz &ext=0, bzw. ?ext=0.

Links zu externen Seiten werden dann im aktuellen Tab/Fenster geöffnet und beim Aufruf interner Seiten wird eine $_GET['ext']-Variable übergeben, so dass diese Seiten die Checkbox abgewählt darstellen und aus ihrem body-Tag heraus ebenfalls linkopener(false) aufrufen.
Und so weiter und so fort...