Erste Ideen

Wenn die Navigation am oberen Fensterrand anstößt, soll sie, obwohl weitergescrollt wird, am oberen Fensterrand bleiben. Dies ließe sich mit folgendem CSS realisieren:

#navigation { position: fixed; top: 8px; }

Der Wert für top ist dabei der gewünschte Minimalabstand zum oberen Fensterrand.

Am Ende dieser Seite wird ein Javascript-Script geladen, welches zunächst einmal die Ereignisüberwachung übernimmt, also prüft, ob das Fenster gescrollt wird. Darauf soll in diesem Artikel nicht weiter eingegangen werden. Eine sehr gute Dokumentation finden Sie bei Mathias Schäfer.

Voraussetzungen schaffen

Zunächst einmal brauchen wir die Originalposition des Navigationselementes in Bezug auf das Browserfenster.

if (document.getElementById("navigation")) { var nav = document.getElementById("navigation"), html = document.getElementsByTagName("html")[0], top_nav = Math.round(nav.getBoundingClientRect().top), top_html = Math.round(html.getBoundingClientRect().top), dist_html_nav = top_nav - top_html; }

Der Quelltext ist folgendermaßen zu lesen:
Wenn ein Element mit der ID "navigation" existiert, besetze die Variable "nav" mit diesem Element. Besetze sodann die Variable "html" mit dem html-Element. Ermittle für beide Elemente den Abstand zum oberen Fensterrand und bilde die Differenz der Abstände. getBoundingClientRect() bezieht sich dabei auf den Außenrand von border. Eine Darstellung des Box-Modells finden Sie im Selfhtml-Wiki.

Nun muss festgestellt werden, ob und wenn ja, wie weit die Seite gescrollt wurde. Das Problem, dass sich dabei auftut, ist, dass die relevanten Browser unterschiedliche Methoden verwenden um die Scrollweite zu ermitteln. Bis auf die Internetexplorer < 9 beherrschen alle pageYOffset, IE7 und 8 ermitteln die Scrollweite über document.documentElement.scrollTop. Glücklicherweise ist es einfach, IE < 9 per feature-detection von den anderen Browsern zu separieren. Das geschieht in folgendem Einzeiler:

window.getComputedStyle ? scrollweite = pageYOffset : scrollweite = document.documentElement.scrollTop;

Dabei handelt es sich um den ternären Operator. (ternär: aus drei Grundeinheiten bestehend)

ausdruck ? tu dies : tu das;

gleichbedeutend mit

if (ausdruck) { tu dies; } else { tu das; }

also, wenn der ausdruckwahr ist, tu dies, wenn nicht, tu das.

In unserem konkreten Fall: Prüfe, ob der Ausdruck window.getComputedStyle wahr ist, der Browser also den Ausdruck window.getComputedStyle versteht. Falls das der Fall ist, ermittle die Scrollweite mit pageYOffset. Anderenfalls, und dies ist für IE < 9 der Fall, ermittle die Scrollweite mit document.documentElement.scrollTop.

Die Funktion für das Fixieren sieht dann wie folgt aus:

function fixieren() { var scrollweite; if (nav) { window.getComputedStyle ? scrollweite = pageYOffset : scrollweite = document.documentElement.scrollTop; if (scrollweite + 8 > dist_html_nav ) { nav.style.position = "fixed"; nav.style.top = "8px"; } else { nav.style.position = ""; nav.style.top = ""; } } }

Die Variable Scrollweite wird vereinbart und nur falls in der Seite ein Element mit der ID navigation existiert, wird die Scrollweite auf die weiter oben erläuterte Weise ermittelt.

Falls dann die Seite soweit gescrollt wurde, dass der obere Rand der Navigation noch 8 Pixel vom oberen Fensterrand entfernt ist, wird sie auf position: fixed; gesetzt und der Abstand zum oberen Fensterrand wird auf 8 Pixel festgelegt. Anderenfalls werden die inline-style-Angaben zurückgesetzt.

Die Festlegungen werden per inline-style gesetzt. Das heißt der Quelltext des HTML-Dokuments wird durch das Javascript wie folgt geändert:

<nav #id="navigation" style="position: fixed; top: 8px;">...</nav>

Per style-Attribut gesetzte CSS-Deklarationen überschreiben gleichlautende im Style-Sheet, es sei denn, sie sind mit !important gekennzeichnet.

Hier noch das vollständige Script:

/* IE < 7 ausschließen */ var nutzbar = false; if (document.body.style.scrollbar3dLightColor != undefined) //IE { if (document.body.style.msInterpolationMode != undefined) //IE > 6 { nutzbar = true; } } else { nutzbar = true; } /* Beginn Ereignisüberwachung */ if (nutzbar) { addEvent(window, "load", fixieren); addEvent(window, "resize", fixieren); addEvent(window, "scroll", fixieren); } /* Ende Ereignisüberwachung */ if (document.getElementById("navigation")) { var nav = document.getElementById("navigation"), html = document.getElementsByTagName("html")[0], top_nav = Math.round(nav.getBoundingClientRect().top), top_html = Math.round(html.getBoundingClientRect().top), dist_html_nav = top_nav - top_html; } function fixieren() { var scrollweite; if (nav) { window.getComputedStyle ? scrollweite = pageYOffset : scrollweite = document.documentElement.scrollTop; if (scrollweite + 8 > dist_html_nav ) { nav.style.position = "fixed"; nav.style.top = "8px"; } else { nav.style.position = ""; nav.style.top = ""; } } }

Die if-Abfragen if (document.getElementById("navigation")) und if (nav) können weggelassen werden, wenn Sie sicherstellen, dass in der Seite, in die das Script eingebunden wird, ein Element mit der ID "Navigation" existiert. Anderenfalls gibt es unschöne Fehlermeldungen.

Wie sie am Verhalten der Navigation sehen können, leistet das beschriebene Script das Verlangte. Dass es jedoch auch Fälle gibt, bei denen das Script versagt, können Sie an der Seite 2a überprüfen.

Seite 1Seite 3