senäh

17senäh und so…

HTML/CSS/JS
25. Okt 2011
Kommentare: 0

Interaktive Slideshows für Präsentationen mit jQuery

Kategorien: HTML/CSS/JS | 25. Okt 2011 | Kommentare: 0

Moinsen Leute! Für eine Präsentation über HTML5 Canvas habe ich mich die letzten Tage mal hingesetzt, um eine jQuery Plugin für Präsentationen zu schreiben, welche komplett in HTML, CSS und JavaScript realisiert sind. Der Vorteil? Ich kann meine Canvas Beispiele direkt in die Folien einbauen. Außerdem kann ich mittlerweile dank CSS3 schicke Animationen realisieren. Auslöser für die Idee war die Slideshow von HTML5Rocks, sowie einige Präsentationen der Google I/O 2011. Den Code, sowie meine gewonnene Erfahrung möchte ich nun mit euch teilen. Live-Beispiele findet ihr etwas weiter unten im Text.

Obwohl es im Grunde nicht schwer ist, eine PowerPoint-artige Slideshow in HTML zu realisieren, bin ich trotzdem auf das ein oder andere Problem gestoßen, mit dem ich mich bisher noch nicht beschäftigen musste. Außerdem bin ich bei der Recherche nach Problemlösungen auf zahlreiche nützliche Links gestoßen. Dabei ist wirklich eine Wulst an Informationen entstanden, die ich jetzt schön aufgliedern möchte.

HTML5 Boilerplate 2.0

Der/die/das Boilerplate ist eines der Themen mit denen ich mich schon lange beschäftigen wollte. Im Web entstand ein ziemlicher Hype um das Projekt – was ziemlich unvermeidbar ist, wenn man HTML5 im Namen trägt und fancy Dropshadows in den Headlines verwendet -, ohne dass ich so richtig kapiert habe was es eigentlich macht. Ich wusste zwar, dass es eine Art Template für HTML5 Projekte war, aber halt nicht wirklich was es genau macht. Ich dachte zum Beispiel, dass es eine Art Blackbox wäre, welche irgendwelche Aufgaben für mich abnimmt ohne mir um diese Sorgen zu machen. Das stimmt so nur bedingt. Denn sobald man sich auch nur mal kurz mit der Boilerplate beschäftigt, wird man feststellen, dass die Boilerplate nicht DIE Lösung für irgendwelche Probleme ist, sondern eine Ansammlung von diversen Lösungen für diverse Probleme aus diversen verschiedenen Quellen. Das heißt, dass die einzelnen Features der Boilerplate sehr unterschiedlich zu benutzen sind.

HTML5 Boilerplate

HTML5 Boilerplate

Einen guten Einstieg in das Thema findet ihr bei nettuts+ mit einem Video von Paul Irish (ja, der hat auch da seine Finger im Spiel). Das Video bezieht sich zwar noch auf Version 1.0, aber der allgemeine Workflow kann auf 2.0 übertragen werden. Ansonsten gibt es auf der Projektseite unzählig weitere Informationen und Videos. Über der/die/das Boilerplate kann man ewig viel erzählen und einen eigenständigen Artikel füllen, darum breche ich an dieser Stelle mal ab und verweise auf der erste Video als Einstieg.

In diesem Projekt habe ich von der Boilerplate aktiv jQuery und Modernizr genutzt und die vorhandene Datenstruktur inkl. normalize.css übernommen.

Sonstige Vorraussetzungen

Neben jQuery und Modernizr verwende ich noch folgende Plugins für die Slideshow:

jquery-mousewheel von brandonaaron

Ein jQuery Plugin für cross-browser Mausrad-Events. Auf diese Weise kann man mit dem Mausrad durch die Folien scrollen.

Das Plugin kann so verwendet werden (direkt aus meinem Quellcode kopiert):

$(document).mousewheel(function(e, delta) {
                        var nextSlide = delta > 0 ? moveRight() : moveLeft();
                        moveSlides(nextSlide);
                        return false;
                    }
            );

Beachtet am Ende false zurückzugeben, damit kein natives Scrollen ausgelöst wird. Mit dem Parameter delta könnt ihr überprüfen, ob nach oben oder nach unten gescrollt wurde.

extendObj von Pipo

Gestern erst vorgestellt; meine angepasste extend-Funktion, welche nur deep copies von Objekten, aber nicht von Arrays erstellt. Diese Funktion brauche ich, um die Defaulteinstellungen meiner Slideshow mit eigenen zu überschreiben. Die Funktion wird genauso benutzt wie die originale extend-Funktion.

Der Quellcode

Mann… so langsam muss ich mich mal bei Github anmelden. Was soll’s. Das Plugin könnt ihr euch hier herunter laden. Und es heißt… ööööh, slideshow.js.

Das Plugin ist lizensiert nach Beerware und kann frei verwendet werden.

Die HTML-Struktur

Um das Plugin zu verwenden benötigt ihr keine starre HTML-Struktur. Ihr seid da flexibel. Im einfachsten Fall sieht euer HTML so aus:

<div id="slides">
    <div class="slide">Slide 1</div>
    <div class="slide">Slide 2</div>
    <div class="slide">Slide 3</div>
</div>

Ob ihr aber nun div’s oder section’s oder was auch immer nutzt, ist egal. Wie ihr den äußersten Wrapper nennt (hier: „#slides“), ist ebenfalls egal. Die Slides im Wrapper haben in den Defaulteinstellungen den Selektor „.slide“, aber diesen könnt ihr mit eigenen Einstellungen überschreiben. Kommen wir doch gleich zum JavaScript-Code, wenn wir schon beim Überschreiben der Einstellungen sind.

Der JavaScript-Code

Der Aufruf der Slideshow über JavaScript funktioniert wie bei jedem anderen jQuery Plugin auch und könnte so aussehen:

jQuery(document).ready(function($) {
    $("#slides").slideshow(config);
});

Wie ihr seht, verwende ich hier „#slides“ als Selektor, wie im oberen Beispiel. Der Parameter config ist optional. Mit diesem könnt ihr folgende Defaulteinstellungen überschreiben:

var defaultOptions = {
                selectors: {
                    slide: ".slide"
                },
                labels: {
                    prevLabels: ["prev", "far-prev"],
                    currentLabel: "current",
                    nextLabels: ["next", "far-next"],
                    distantLabel: "distant"
                },
                slideTransitionClass: "transition",
                slidesUpdateAnimationClass: "on-change-animation",
                startSlide: 0,
                startScale: 0.95,
                loopPresentation: false
            };

Unter selectors.slide gebt ihr – welche Überraschung – den Selektor für die Slides an. Eventuell kommen in späteren Versionen des Plugins hier noch weitere relevante Selektoren hinzu, weswegen ich sie gleich in einem Objekt bündele.

Unter selectors.labels speichere vier mögliche Arten von dynamischen Klassennamen ab, welche vier unterschiedliche Status (japp, das ist der Plural) der Slides darstellen:

  • currentLabel: Der Klassenname des aktuellen Slides.
  • prevLabels: Eine variable Anzahl von Klassennamen für die Slides vor dem aktuellen Slide.
  • nextLabels: Eine variable Anzahl von Klassennamen für die Slides nach dem aktuellen Slide.
  • distantLabel: Der Klassenname für alle Slides, welche nicht durch die obigen Labels abgedeckt werden.

In der Praxis könnte es dann so aussehen, dass ihr den current Slide in der Mitte des Bildschirms anzeigt, die prev Slides links daneben, die next Slides rechts daneben und die distant Slides schaltet ihr einfach unsichtbar. Da für die prev und next Slides Arrays verwendet werden, könnt ihr hier ganz individuell eure Präsentation in CSS stylen. So könntet ihr beispielsweise komplett auf prev Slides verzichten oder aber drei next Slides verwenden. Wie die Präsentation dann aussehen könnte seht ihr bei Beispiel 3.

Mit slideTransitionClass wird auf die Slides eine Klasse gesetzt, in der die Transitioneinstellungen von CSS3 für die Slides festgehalten sind. Wollt ihr eure Slides nicht animieren, könnt ihr auch komplett auf diese Klasse verzichten. Ich habe für die Transitions eine eigene Klasse erstellt, um sie  erst dann hinzuzufügen, wenn die Slides in ihrer Ausgangsposition sind. (Ansonsten würde sie beim ersten Öffnen der Präsentation animiert in ihre Positionen geschoben werden. Ich wollte aber, dass sie sofort in ihrer Ausgangsposition sind.)

Mit slidesUpdateAnimationClass kann der Wrapper der Slides animiert werden. Ich verwende hier CSS3 Animationen – KEINE CSS3 Transitions! Warum? Animationen erlauben mehr feintuning als Transitions und sind bei einem einzelnen Objekt (ein Wrapper anstatt mehrere Slides) einfacher zu verwenden. Bei einem der Beispiele wollte ich, dass der Wrapper bei einem Folienwechsel kleiner und dann wieder größer skaliert wird. Dabei weiß ich nicht, welche Skalierung der Wrapper ursprünglich besitzt. Ich möchte nur, dass er kleiner wird und dann wieder zu seiner Ursprungsgröße zurückkehrt. Das funktioniert nur mit CSS3 Animationen, da ich hier zu einem bestimmten Wert animieren kann (meine kleine Skalierung) und diese Animation dann noch einmal rückwärts abspielen kann (zur ursprünglichen Skalierung, ohne zu wissen, welchen Wert diese genau hat).

Mit startSlide gebt ihr an, bei welcher Folie die Präsentation beginnen soll.

Mit startScale gebt ihr die Ausgangsskalierung des Wrappers an. Ich verwende hier 0.95, damit man die prev und next Slides am Bildschirmrand sehen. (Auf diese Weise kann ich bei den Slides in den CSS-Einstellungen trotzdem als Höhe und Breite 100% angeben. Für mich persönlich lässt sich das einfacher rechnen. Ich gehe davon aus, dass die Slides bildschirmfüllend sind, ich aber leicht herauszoome.)

Bei loopPresentation übergebt ihr true, wenn ihr nach der letzten Folie wieder zur ersten zurückspringen möchtet.

Benutzung

Mit den Pfeiltasten, dem Mausrad und der Leertaste könnt ihr euch durch die Slideshow navigieren. Mit Plus und Minus könnt ihr in die Präsentation hinein oder herauszoomen. Drückt ihr auf 0 geht ihr zurück auf die ursprüngliche Zoomstufe.

Hierbei wird übrigens die gesamte Slideshow skaliert! Möchtet ihr nur die Textgröße ändern, könnt ihr wie bei jeder anderen Internetseite auch Strg+Plus/Command+Plus bzw. Strg+Minus/Command+Minus verwenden.

Beispiele

Nun zu ein paar Beispielen. So könnte eure Slideshow aussehen!

Hinweis: Ich rate euch dringend die Slideshows im Chrome Browser anzusehen. Ich habe sie fürs erste lediglich auf diesem getestet und optimiert. In Version 15 laufen die Animation für meine Bedürfnisse und auf meinem Rechner aber ausreichend smooth.

Bei Beispiel 1 wandern die Slides einfach von rechts nach links. Bei einem Wechsel zoomt die Slideshow kurz heraus.

Slideshow - Beispiel 1

Slideshow - Beispiel 1

In Beispiel 2 bewegen sich die Slides in einer Rotationsbewegungen über den Bildschirm. Auch hier zoomt die Slideshow bei einem Wechsel kurz heraus.

Slideshow - Beispiel 2

Slideshow - Beispiel 2

Im letzten Beispiel habe ich komplett auf die Darstellung vorhergehender Slides verzichtet und zeige stattdessen die nächsten drei Slides an. Die Slides sind deswegen auch nicht mehr Bildschirmfüllend. Alle anderen Slides werden bei einem Folienwechsel einfach klein skaliert. Auf eine Animation des Wrappers bei einem Folienwechsel habe ich dieses Mal verzichtet.

Slideshow - Beispiel 3

Slideshow - Beispiel 3

Fun fact am Rande: Alle Hintergründe wurden komplett in CSS3 gestylt. Hier erfahrt ihr wie.

Lessons learned

Nun zum spannenden Teil für alle Entwickler. Was habe ich bei dem Projekt gelernt?

CSS3

CSS3 ist ein echt feines Spielzeug – wenn es denn funktioniert! Es gibt noch zu viele Unterschiede zwischen den Browsern und die Spezifikation ist noch nicht final. Selbst wenn ein Browser eine bestimmte Funktion unterstützt, ist die Performance häufig miserabel. Chrome legt hier schon eine super Arbeit ab. Ich habe versucht mir die Slideshows einmal in Firefox anzuschauen, aber hier waren die Animationen und Transitions sehr ruckelig. In Chrome läuft alles viel flüssiger. Dennoch ist auch Chrome nicht von Fehlern gefeit. Ursprünglich habe ich meine Slide mit translate(x, y); bewegt, anstatt mit eine absoluter Positionierung, aber dies hat teilweise zu merkwürdigen Flackereffekten geführt, wenn ich den Wrapper skaliert habe.

Sollte man CSS3 also schon in der Praxis verwenden? Kaum! Vielleicht in 5% der Fälle. In einer abgeschlossenen Umgebung ist das okay. So wie bei mir. Ich möchte eine Präsentation auf meinem Laptop mit meinem Browser halten. Hier weiß ich wie alles aussieht und wie es funktioniert. Ich kann CSS3 in dem Maße verwenden, wie es meine Arbeitsumgebung zulässt. Wenn ich nach dem Progressive Enhancement Muster arbeite, kann ich CSS3 an manchen Stellen ebenfalls bereits einsetzen bei denen es nicht stört, wenn ein Browser CSS3 nicht unterstützt. So könnte man beispielsweise die Farbe eines Links beim Hovern mit einer Transition einfaden. Wenn der Browser keine Transitions kennt, würde die Farbe einfach sofort umgeschalten werden.

Was muss ich beachten, wenn ich CSS3 bereits verwenden möchte? Zuerst einmal sollte man sich vor Augen halten, was CSS3 alles kann. Eine gute und sehr ausführliche Übersicht findet ihr auf css3files.com. Hier lernt ihr eigentlich alles, was ihr benötigt.
Sehr nützlich kann aber auch noch die Seite css3please.com sein, in der es eine Übersicht über alle Prefixe für die cross-browser Kompatibilität gibt (etwas aktueller als bei css3files.com). (Überraschung! Hier sitzt mal wieder Paul Irish mit an Bord.)
Nützlich ist ebenfalls die Modernizr.prefixed() Funktion, wenn ihr dynamisch CSS3 verwenden möchtet. Ihr übergebt der Funktion lediglich einen String, die entsprechend für den Browser des Nutzers geprefixed werden muss und könnt dann wie gewohnt auf die CSS-Werte zugreifen. Ich skaliere auf diese Weise mit Shortcuts die Slideshows. Hier der entsprechende Code:

var scaleSlides = function(nextScale) {
                var prefixedTransform = Modernizr.prefixed("transform");
                $this.css(prefixedTransform, "scale(" + nextScale + ")");
                currentScale = nextScale;
            };

Apropos Shortcuts…

Tasteneingabe, Shortcuts und Keycodes in JavaScript

Wie kompliziert können Dinge eigentlich sein? Bisher musste ich mich nie mit der Abfrage von Tasten über JavaScript auseinander setzen, aber mich graust es jetzt schon davor einmal richtige HTML5 Spiele zu entwerfen. Ich hätte nie erwartet, dass es so kompliziert werden würde, einfache Tasteneingaben zu handhaben.

Generell werden Tasten über einen sogenannten Keycode referenziert. Die Idee ist, dass jede Taste eine ID hat und wenn ich diese ID habe, weiß ich welche Taste gedrückt würde. Nun zu den Problemen. Die Keycodes für jede Taste und wie man sie abfragt, kann sich sowohl von Browser zu Browser, als auch von Betriebssystem zu Betriebssystem unterscheiden. Außerdem werden manche Tasten als spezielle Metakeys gesondert referenziert. Dies ist zum Beispiel bei Strg der Fall. Dummerweise aber nicht bei Cmd, obwohl Cmd unter Mac nahezu die gleichen Funktionen besitzt wie Strg unter Windows. Und zu guter letzt kann ein und dieselbe Taste im gleichen Browser auf dem gleichen Betriebssystem je nach Tastenevent (keydown bzw. keypress) einen unterschiedlichen Keycode besitzen. Wow. Wer noch mehr im Detail wissen möchte, findet hier weitere Infos.

Nun seid ihr gefragt! Kennt ihr eine Library, die sich mit dem Problem beschäftigt? Ich habe nichts brauchbares im Internet finden können, aber ich kann mir einfach nicht vorstellen, dass es dazu nichts gibt. Tasteneingabe und Shortcuts werden doch in jeder größeren Webapp benötigt. Irgendwer muss doch da schon einmal die Verwendung vereinfacht haben…

jQuery versucht den Ablauf der Abfragen auf jeden Fall schon etwas mit e.which zu generalisieren.

CSS3 Transitions und Animations mit JavaScript steuern

Ja ja… Manche HTML5 Standards werden von den Browsern schon sehr gut unterstützt. Canvas zum Beispiel. Aber CSS3 lässt da – wie oben bereits erwähnt – noch etwas zu wünschen übrig. Dieses Problem verschärft sich noch einmal, wenn man Transitions und Animations über JavaScript steuern möchte. AnimationEvents funktionieren nach meiner Recherche wohl erst in Webkitbrowsern (z.B. webkitAnimationEnd für das Ende einer Animation) und in Firefox (z.B. animationend für das Ende einer Animation).

Na gut, jetzt muss ich aber auch mal zu einem Ende kommen. Ich hoffe, ich konnte mit diesem Artikel den ein oder anderen helfen.

Falls ihr meine Slideshow irgendwie nutzen solltet, würde ich mich freuen, wenn ihr mir einen Link zu eurem Projekt in den Kommentaren hinterlasst.

Autor: Pipo

...kommt ursprünglich aus der Designerecke, ist aber im Laufe seines Studiums in die Webentwicklung gestolpert. Kann sich seit dem nicht so richtig entscheiden wo er hingehört und wagt deswegen vielleicht die Flucht nach vorne in ein komplett neues Gebiet. Vielleicht Management? Niemand weiß es. Auch er nicht.