vorige Präsentation: Unobstrusive Javascript | zurück zum Buch-Kapitel [esc] | Nächste Präsentation Besondere Javascript-Schreibwesen in jQuery
Die Library jQuery unterstützt das Prinzip der „graceful degradation“ – auch ohne Javascript sind Webseiten mit jQuery immer noch gut verwendbar. Dieses Prinzip wird auch „progressive enhancement“ genannt, und bezieht sich nicht nur auf Javascript, sondern auch auf andere „Zusatz-Technologien“ wie z.B. Flash.
Die Idee ist dabei immer die Gleich: man baut die Webseite zuerst ohne Javascript, und fügt dann Javascript hinzu (ohne die Verwendbarkeit ohne Javscript zu zerstören). Der Inhalt (Content) der Webseite bleibt auch ohne Javascript zugänglich.
Von dieser Herangehensweise profitieren nicht nur Blinde, Menschen mit veralteten Browsern oder exotischen Ausgabegeräte. Auch für Suchmaschinen wie Google oder andere Programme die die Information aus den Webseiten weiter verarbeiten ist dieses Prinzip hilfreich.
Um zu testen, ob das wirkliche funktioniert kann man ganz einfach mit dem Firefox-AddOn QuickJava testen. Wie hier gezeigt kann Javascript mit einem Klick deaktiviert werden.
Es gibt Websites, bei denen dieser Ansatz nicht funktionieren kann. z.B. für einen Shooter als Browsergame kann man nicht nicht eine Alternative ohne Javascript anbieten.
Für viele Apps funktioniert das aber. Probieren Sie z.B. gmail ohne javascript aus, oder das Webmail der FH (zimbra). Die Interaktion ist etwas umständlicher, aber man kann alle Features der Mail benutzen.
Die Aufgabenstellung: ein einer langen Webseite sind mehrere Anker-Punkte
mit <a name=...>
gesetzt, über ein Navigationsmenü soll man diese erreichen
können. Diese Seite zeigt ein funktionierendes
Beispiel (letzte Version).
Wir beginnen mit völlig problemlosem HTML
<div id="navigation"> <a href="#s0">Thema 0</a> <a href="#s1">Thema 1</a> ... </div> <section id="s0"> <h2>Thema 0</h1> <p>bla bla ...</p> </section> <section id="s1"> <h2>Thema 1</h1> <p>bla bla ...</p> </section> ...
#navigation { position: fixed; z-index: 10; bottom: -1px; }
In einem Versuch die Seite zu verbessern ersetzen wir nun die Links durch den Aufruf einer Javascript-Funktion:
<div id="navigation"> <a onClick="scrollToMe('#s0')">Thema 0</a> <a onClick="scrollToMe('#s1')">Thema 1</a> ... </div>
Die Javsacript-Funktion verwendet jQuery und die übergebene
ID um den Ziel des Links ausfindig zu machen, und dann die
jQuery Methode offset
um die Position des Ziels im Dokument
zu berechnen.
Mit der jQuery-Methode animate
wird dann eine Animation erzeugt:
binnen 800 Millisekunden wird die Seite durch setzen von scrollTop
von der aktuellen Scrollposition in die Scrollposition gebracht,
die das Ziel ganz oben im Fenster anzeigt.
Mit return false
wird die “normale” Funktion des Links deaktiviert.
function scrollToMe(id) { var top = $(id).offset().top; $('body').animate({ scrollTop: top }, 800); return false; }
Diese Version ist kein Beispiel für gutes Javascript:
in manchen Browsern funktioniert das Scrollen der Seite mit scrollTop
nicht.
Mit dieser Version haben wir
Wir haben dabei beide Prinzipien gebrochen
Im nächsten Versuch werden wir jQuery verwenden, um unobstrusive zu programmieren:
Die Navigation wird wieder zurück-gestellt auf normale HTML-Links:
<div id="navigation"> <a href="#s0">Thema 0</a> <a href="#s1">Thema 1</a> ... </div>
An diese Links wird ein neuer Eventhandler angefügt, abernicht mit onclick
im HTML, sondern mit jquery.
$(document).ready( function () { $('#navigation a').on('click', scrollToMe); });
Die Funktion scrollToMe
wird als Eventhandler implementiert:
sie erwartet ein Event als Argument und die angeklickte Node
in der Variablen this
.
Ausserdem verwendet die Funktion
die jQuery-Methode preventDefault
um das “normale” Verhalten
des Links zu unterbinden.
function scrollToMe(event) { var link = $(this).attr('href'), top = $(link).offset().top; $('body').animate({ scrollTop: top }, 800); event.preventDefault(); }
Diese Variante funktioniert schon besser:
Wir haben damit schon ein Prinzip eingehalten, und sind beim anderen Prinzipien auf halben Weg
Im nächsten Schritt werden wir sicher stellen, dass die Animation nur in solchen Browsern verwendet wird, wo sie auch funktioniert.
Achtung: hier gibt es einen falschen und einen richtigen Ansatz:
Die erste Variante funktioniert nicht: die Selbstoffenbarung der Browser kann falsch sein, ich kenne nicht alle Browser und ihre Fähigkeiten. Siehe auch Feature & Browser Detection im jQuery learning center
Die Funktion scrollToMe
bleibt unverändert.
Wir testen ob die Funktion scrollTop wirklich den Wert
von scrollTop verändern kann. Wenn das funktioniert wird
die globale Variable can_scroll
auf true
gesetzt,
andernfalls auf false
.
// try out scrollTop, // set global Flag can_scroll var old_scrolltop = $('body').scrollTop(); $('body').scrollTop(10); window.can_scroll = ( $('body').scrollTop() > 0 ); $('body').scrollTop(old_scrolltop); if ( window.can_scroll ) $('#navigation a').on('click', scrollToMe);
Diese Herangehensweise - Feature Detection, dann Flags setzen, die im weiteren Code verwendet werden können - wird von der Library modernizr für eine lange Liste von Features angeboten.
Diese Variante behebt das Problem mit nicht-funktionierenden Javascript-Browsern:
Es bleibt aber noch in Problem:
In der klassischen Version ändert sich beim navigieren zwischen den Ankern jeweils die URL im Browser. Wenn ich ein Ziel annavigiere, und dann die URL kopiere um einen Link zu setzen / mir eine Bookmark setze, dann verweist die URL die ich verwende wirklich wieder genauf auf das Ziel.
Dieses Verhalten ist erstrebenswert, wird aber von der “animierten” Version derzeit nicht geliefert.
(Diese “Navigierbarkeit” ist auch ein klassisches Problem von AJAX-Applikationen, die Lösung die wir hier entwickeln funktioniert auch dort)
In die Funktion scrollToMe
wird eine Zeile eingefügt.
function scrollToMe(event) { var link = $(this).attr('href'); ... window.history.pushState( {}, "Thema " + link, link); }
Mit dem window.history
Objekt kann man den Browser von Javascript aus “navigieren”:
mit history.back()
zum Beispiel einen Schritt zurück gehen.
Mit history.pushState()
kann man zu einer neuen Seite navigieren,
sie wird dabei an die History angefügt - das ist das “normale” Verhalten
des Browsers.
Eine Alternative ist history.replaceState()
- dabei wird die aktuelle Seite
ersetzt, die Browser-History wird nicht länger.
Beide Methoden erwarten drei Argumente - ein Objekt und zwei Strings - aber nur das letzte Argument wird derzeit benutzt. Es ist ein String mit der URL die geladen werden soll.
Mit dieser Variante haben wir für die Javascript-Browser alle Funktionalität der einfachen HTML-Version wiederhergestellt. Und zusätzlich gibt es eventuell noch eine schöne Animation.
Damit sind beide Prinzipien voll erfüllt:
vorige Präsentation: Unobstrusive Javascript | zurück zum Buch-Kapitel [esc] | Nächste Präsentation Besondere Javascript-Schreibwesen in jQuery
/
#