Slider als Keyframe-Animation mit CSS3 So kommt ohne Javascript Bewegung in die Sache

Mit den @keyframes-Regeln von CSS3 stehen Werkzeuge zur Verfügung, die Darstellung von Inhalten einer Website zeitgesteuert zu verändern. Um die Möglichkeiten sowie die Vor- und Nachteile im Vergleich zum Einsatz von Javascript etwas näher zu untersuchen, wird hier der Ansatz aus Imageslider ohne Javascript weiterverfolgt und der Slider um einen zeitgesteuerten Ablauf ergänzt.

Konzeptskizze für einen CSS-Slider

Grundlagen - was sind Keyframe-Animationen

Keyframe-Animationen bieten die Möglichkeit, die Darstellung von HTML-Elementen über eine Zeitspanne hinweg zu verändern. Es lassen sich beliebig viele Zwischenstufen der Darstellung (Keyframes) definieren, der Browser berechnet die Übergänge dazwischen - es entsteht Bewegung.

Wir brauchen also zweierlei Dinge:

  1. Die Definition der Darstellung eines Elements zu verschiedenen Zeitpunkten
  2. Die Zuweisung der Definition (inkl. Angaben zum Ablauf) zu einem Element

Keyframe-Animationen definieren

Im einfachsten Fall wird ein Start- und ein Endzustand definiert, es können aber auch beliebig viele Zwischenstufen (Keyframes) eingefügt werden. Für jeden Keyframe kann man beliebigen CSS-Eigenschaften (diese sollten natürlich animierbar sein) Werte zuweisen. Allgemein ausgedrückt sieht eine Animation wie folgt aus:

@keyframes nameDerAnimation {
	x% {
		Eigenschaft01: Wert;
		Eigenschaft02: Wert;
	}

	y% {
		Eigenschaft01: Wert;
		Eigenschaft02: Wert;
	}

	z% {
		Eigenschaft01: Wert;
		Eigenschaft02: Wert;
	}
}

Derzeit werden Vendor-Präfixe für webkit-basierte Browser noch benötigt, sind hier zur besseren Lesbarkeit jedoch nicht aufgeführt.

Zuweisung einer Animation

Eine Animation lässt sich über folgende CSS-Eigenschaften steuern

Essentiell sind der Name und die Dauer der Animation. In Kurzschreibweise lassen sich diese Eigenschaften unter animation zusammenfassen. Die Zuweisung einer Animation zu einem Element E sieht also mindestens wie folgt aus:

E {
	animation: name duration;
}

Einen Überblick über die verschiedenen Eigenschaften und mögliche Werte findet sich unter http://www.w3.org/TR/css3-animations/. Auch hier werden die Vendor-Präfixe für die Unterstützung der Webkit-Browser noch benötigt.

Slider - Grundfunktion

Nehmen wir uns den angestrebten Slider vor. Dieser besteht in Sachen HTML, wie in Mainova AG beschrieben, aus einer unsortierten Liste für die Slides und Radiobuttons sowie zugehörige Labels zur Steuerung. Der prinzipielle Aufbau des Codes, angereichert mit ein paar zusätzlichen Klassen, die im weiteren Verlauf das Leben leichter machen:

Die einzelnen Slides sind gefloatet, die Position der Liste soll sich je Schritt (Keyframe) um die Breite eines Listenpunktes im Sichtfenster weiterschieben. In der Annahme, dass der Slider aus vier Slides besteht, hat jeder Slide genau 25% der gesamten Zeit der Animation zur Verfügung. Diese Zeit teilt sich dann nochmal in die Standzeit (hier 15%) und die Animationszeit (hier 10%) eines Slides. Die Notation der Animation sieht demnach wie folgt aus:

@keyframes slider {
	0%, 15% {left: 0;}
	25%, 40% {left: -100%;}
	50%, 65% {left: -200%;}
	75%, 90% {left: -300%;}
	100% {left: -400%;}
}

.slideList {
	animation-name: slider;
	animation-duration: 20s;
	animation-delay: 2s;
	animation-iteration-count: infinite;
}

Die Angaben kann man natürlich in Kurzschreibweise notieren (s.u.), sind hier jedoch zur besseren Lesbarkeit ausgeschrieben. Notwendige Eigenschaften sind in diesem Fall der Name der Animation, die Dauer und die Wiederholung. Die Verzögerung wird nötig, da bei manueller Steuerung der Slider langsam verschoben wird, die Animation also erst starten darf, wenn die Verschiebung abgeschlossen ist.

Bauen wir die Animation in dieser Form, wird, wie nicht anders zu erwarten, im letzten Schritt der Slider komplett ins Nirwana (-400%) geschoben, es bleibt also nur noch Luft im Sichtfenster übrig. Wir brauchen demzufolge noch eine Möglichkeit, statt dieser Luft den ersten Slide noch einmal zu sehen, bevor die Animation wieder von vorne startet.

Die Luft ist raus

Die Idee ist eigentlich ganz simpel. Wir definieren für den ersten Slide eine weitere Keyframe-Animation, die diesen unmittelbar bevor der letzte Verschub des Sliders stattfindet (bei 90%), nahtlos an seinem Ende anfügt. Danach starten beide Animationen wieder von vorne und es entsteht der Eindruck eines Endlosbandes. Die Stylesheet-Anweisungen dazu:

@keyframes slide01ToEndStart01 {
	89.99% {left: 0;}
	90%, 100% {left: 100%;}
}

.slide {
	position: relative;
}

.slide01 {
	animation: slide01ToEndStart01 20s 2s infinite;
}

Damit haben wir einen voll funktionstüchtigen Slider, allerdings noch ohne Steuerelemente. Diese kommen im nächsten Schritt.

Steuerungsmöglichkeit für den Benutzer

Die Steuerelemente funktionieren vom Prinzip identisch zu dem in Mainova AG beschriebenen Szenario über die Pseudoklasse :checked (Checkbox-Hack). Diese Variante läuft auch hier prima, allerdings stolpern wir über das Problem, dass die einmal zugewiesene Animation ohne Unterlass weiterläuft. D.h. bei Klick auf einen Radiobutton rutscht der Slider zwar kurz zur passenden Position, aber dann greift direkt wieder die bei Seitenaufruf gestartete Animation und es wird zum nächsten Keyframe in ihrem Ablauf gesprungen. Zu verhindern wäre dies, wenn nach jeder Wahl eines Radiobuttons (also dem Sprung zu einem bestimmten Slide) die Animation bei eben diesem Slide wieder von vorne losläuft. Da es keine Möglichkeit gibt, einen anderen Startpunkt als 0 für eine Animation zu definieren, bleibt nur übrig, jeweils eine separate Keyframe-Animation zu erstellen und diese in Abhängigkeit des Status der Radiobuttons zuzuweisen. Das könnte dann wie folgt aussehen:

@keyframes slidesStart01 {
	0%, 15% {left: 0;}
	25%, 40% {left: -100%;}
	50%, 65% {left: -200%;}
	75%, 90% {left: -300%;}
	100% {left: -400%;}
}

@keyframes slidesStart02 {
	90.01% {left: 0;}
	0%, 15%, 100% {left: -100%;}
	25%, 40% {left: -200%;}
	50%, 65% {left: -300%;}
	75%, 90% {left: -400%;}
}

@keyframes slidesStart03 {
	65.01% {left: 0;}
	0%, 15%, 100% {left: -200%;}
	25%, 40% {left: -300%;}
	50%, 65% {left: -400%;}
	75%, 90% {left: -100%;}
}

@keyframes slidesStart04 {
	40.01% {left: 0;}
	0%, 15%, 100% {left: -300%;}
	25%, 40% {left: -400%;}
	50%, 65% {left: -100%;}
	75%, 90% {left: -200%;}
}

.slideList{
	animation: 20s 2s infinite;
	transition: left 2s;
}

#slide01:checked ~ .slideList {
	animation-name: slidesStart01;
	left: 0;
}

#slide02:checked ~ .slideList {
	animation-name: slidesStart02;
	left: -100%;
}

#slide03:checked ~ .slideList {
	animation-name: slidesStart03;
	left: -200%;
}

#slide04:checked ~ .slideList {
	animation-name: slidesStart04;
	left: -300%;
}

Soweit, so gut - aber drei Problemstellen gibt es noch. Erstens muss der erste Slide passend zur jeweils aktiven Animation des Sliders verschoben werden, zweitens lässt sich nicht noch einmal zum aktuell ausgewählten Slide springen und drittens sollten sich die Kontrollelemente natürlich auch dem Status der Animation anpassen.

Position des ersten Slides

Da die Animation jeweils bei einem anderen Slide startet, müssen wir für den ersten Slide weitere Keyframe-Animationen anlegen, damit er zum jeweils passenden Zeitpunkt verschoben wird.

@keyframes slide01ToEndStart01 {
	89.99% {left: 0;}
	90%, 100% {left: 100%;}
}

@keyframes slide01ToEndStart02 {
	49.99%, 90.01% {left: 0;}
	50%, 90% {left: 100%;}
}

@keyframes slide01ToEndStart03 {
	24.99%, 65.01% {left: 0;}
	25%, 65% {left: 100%;}
}

@keyframes slide01ToEndStart04 {
	40.01% {left: 0;}
	0%, 40% {left: 100%;}
}

#slide01:checked ~ .slideList .slide01 {
	animation-name: slide01ToEndStart01;
}

#slide02:checked ~ .slideList .slide01 {
	animation-name: slide01ToEndStart02;
}

#slide03:checked ~ .slideList .slide01 {
	animation-name: slide01ToEndStart03;
}

#slide04:checked ~ .slideList .slide01 {
	animation-name: slide01ToEndStart04;
}

Doch damit nicht genug. Es kann passieren, das wir in dem Moment manuell zu einem anderen Slide springen, in dem der erste Slide schon durch die Animation verschoben wurde. Die Position muss also bei Klick auf einen Steuerelement wieder auf Null gesetzt werden. Da der gesamte Slider jedoch langsam verschoben wird (Transition), darf der erste Slide nicht sofort zurückgesetzt werden, sondern mit einer entsprechenden Verzögerung. Diese wird per transition-delay gesteuert:

.slide {
	transition: left 0s .5s;
}

#slide04:checked ~ .slideList .slide {
	transition-delay: 2s;
}

Volle Kontrolle

Der aktuell markierte Slide kann bis jetzt nicht wieder angewählt werden. Ist auch logisch, da die Animation nicht den Zustand der Radiobuttons steuert, der einmal gewählte also so lange ausgewählt bleibt, bis man einen anderen anklickt. Ein erneuter Klick auf einen ausgewählten Radiobutton löst keine neue Animation aus. Wenn man mit dieser Einschränkung nicht leben möchte, kann man mit einer doppelten Steuerung arbeiten. Die Idee ist, die Anzahl der Radiobuttons zu verdoppeln und die beiden Hälften mit zwei getrennten Zusammenstellungen von Labels zu steuern. Durch die Trennung, lassen sich die beiden Labelgruppen jeweils wechselseitig sichtbar schalten - ist ein zur ersten Steuerung zugehöriger Radiobutton ausgewählt, wird die zweite Gruppe von Labeln angezeigt und umgekehrt. Wir brauchen also etwas zusätzlichen HTML-Code:

Dieses zusätzliche Markup zieht einen Rattenschwanz an weiteren Stylesheets nach sich. Da bei jedem Klick auf ein Label, die zugehörige Animation von vorne starten muss, können wir den Buttons der zweiten Gruppe nicht die gleichen Animationen zuordnen. Folgendes reicht leider nicht:

#slide01:checked ~ .slideList,
#slide101:checked ~ .slideList {
	animation-name: slidesStart01;
	left: 0;
}

Es müssen die gleichen Animationen unter einem neuen Namen angelegt und separat aufgerufen werden - z.B. so:

@keyframes slidesStart01 {
	0%, 15% {left: 0;}
	25%, 40% {left: -100%;}
	50%, 65% {left: -200%;}
	75%, 90% {left: -300%;}
	100% {left: -400%;}
}

#slide01:checked ~ .slideList {
	animation-name: slidesStart01;
	left: 0;
}

@keyframes slidesStart101 {
	0%, 15% {left: 0;}
	25%, 40% {left: -100%;}
	50%, 65% {left: -200%;}
	75%, 90% {left: -300%;}
	100% {left: -400%;}
}

#slide101:checked ~ .slideList {
	animation-name: slidesStart101;
	left: 0;
}

Analog hierzu wird der gleiche Schritt auch für die Animationen, die den ersten Slide ans Ende schieben, notwendig.

Hervorhebung der Labels

Zur Kennzeichnung des zum jeweils ausgewählten Radiobuttons zugehörigen Labels werden ebenfalls Keyframe-Animationen definiert. Hier muss wie bereits gewohnt für jeden Startpunkt wieder eine separate Definition erstellt werden, was dann für die erste Labelgruppe wie folgt aussehen kann:

@keyframes slideControl01 {
	24.99% {background: #68b022;}
	25%, 100% {background: none;}
}

@keyframes slideControl02 {
	24.99%, 50% {background: none;}
	25%, 49.99% {background: #68b022;}
}

@keyframes slideControl03 {
	49.99%, 75% {background: none;}
	50%, 74.99% {background: #68b022;}
}

@keyframes slideControl04 {
	74.99% {background: none;}
	75%, 100% {background: #68b022;}
}

.slideControl label {
	animation: 20s 2s infinite;
}

#slide01:checked ~ .slideControl label[for="slide01"],
#slide02:checked ~ .slideControl label[for="slide02"],
#slide03:checked ~ .slideControl label[for="slide03"],
#slide04:checked ~ .slideControl label[for="slide04"] {
	animation-name: slideControl01;
	background: #68b022;
}

#slide01:checked ~ .slideControl label[for="slide02"],
#slide02:checked ~ .slideControl label[for="slide03"],
#slide03:checked ~ .slideControl label[for="slide04"],
#slide04:checked ~ .slideControl label[for="slide01"] {
	animation-name: slideControl02;
}

#slide01:checked ~ .slideControl label[for="slide03"],
#slide02:checked ~ .slideControl label[for="slide04"],
#slide03:checked ~ .slideControl label[for="slide01"],
#slide04:checked ~ .slideControl label[for="slide02"]  {
	animation-name: slideControl03;
}

#slide01:checked ~ .slideControl label[for="slide04"],
#slide02:checked ~ .slideControl label[for="slide01"],
#slide03:checked ~ .slideControl label[for="slide02"],
#slide04:checked ~ .slideControl label[for="slide03"] {
	animation-name: slideControl04;
}

Die zweite Gruppe wird analog gesteuert und die Sichtbarkeit der Gruppen über die Positionierung mit folgendem Code geregelt:

.control01:checked ~ .slideControl01,
.control02:checked ~ .slideControl02 {
	left: -5000px;
}

Damit ist man durch und hat einen komplett funktionstüchtigen Slider inkl. Steuerelemente für beliebige Inhalte, der ohne eine Zeile Javascript auskommt.

Fazit

Man kann mittlerweile eine rein CSS-basierte Lösung für Slider und ähnliche Bausteine schreiben, die sogar von den meisten Browsern verstanden wird, d.h. mit Vendor-Präfix kommt so ziemlich jeder moderne Browser damit klar. Eine ausführliche Übersicht, welche Browser Keyframe-Animationen unterstützen gibt es auf caniuse.com.

Unbestritten ist sicherlich der Mehraufwand, im Vergleich zur Verwendung einer fertigen (Javascript-)Lösung. Wobei man die dem CSS-Code zugrundeliegende Logik natürlich auch mit einer beliebigen Programmiersprache abbilden und ihn so automatisch erzeugen lassen kann.

Andere Verhalten, als der Verschub von rechts nach links (Überblendungen, Drehungen, Skalierungen etc.) lassen sich über die Manipulation der entsprechenden CSS-Eigenschaften natürlich problemlos bauen.

So sieht es aus

  • Kegelschnitte

  • Maßaufgaben

    Maßaufgaben

  • Würfelkomposition

    Würfelkomposition

  • Schnitt Zylinder - Hyperboloid

    Schnittkurve von Zylinder und Hyperboloid

/* Definition der Animationen */
/* 1. Bewegung des Sliders */
@keyframes slidesStart01 {
	0%, 15% {left: 0;}
	25%, 40% {left: -100%;}
	50%, 65% {left: -200%;}
	75%, 90% {left: -300%;}
	100% {left: -400%;}
}

@-webkit-keyframes slidesStart01 {
	0%, 15% {left: 0;}
	25%, 40% {left: -100%;}
	50%, 65% {left: -200%;}
	75%, 90% {left: -300%;}
	100% {left: -400%;}
}

@keyframes slidesStart101 {
	0%, 15% {left: 0;}
	25%, 40% {left: -100%;}
	50%, 65% {left: -200%;}
	75%, 90% {left: -300%;}
	100% {left: -400%;}
}

@-webkit-keyframes slidesStart101 {
	0%, 15% {left: 0;}
	25%, 40% {left: -100%;}
	50%, 65% {left: -200%;}
	75%, 90% {left: -300%;}
	100% {left: -400%;}
}

@keyframes slidesStart02 {
	90.01% {left: 0;}
	0%, 15%, 100% {left: -100%;}
	25%, 40% {left: -200%;}
	50%, 65% {left: -300%;}
	75%, 90% {left: -400%;}
}

@-webkit-keyframes slidesStart02 {
	90.01% {left: 0;}
	0%, 15%, 100% {left: -100%;}
	25%, 40% {left: -200%;}
	50%, 65% {left: -300%;}
	75%, 90% {left: -400%;}
}

@keyframes slidesStart102 {
	90.01% {left: 0;}
	0%, 15%, 100% {left: -100%;}
	25%, 40% {left: -200%;}
	50%, 65% {left: -300%;}
	75%, 90% {left: -400%;}
}

@-webkit-keyframes slidesStart102 {
	90.01% {left: 0;}
	0%, 15%, 100% {left: -100%;}
	25%, 40% {left: -200%;}
	50%, 65% {left: -300%;}
	75%, 90% {left: -400%;}
}

@keyframes slidesStart03 {
	65.01% {left: 0;}
	0%, 15%, 100% {left: -200%;}
	25%, 40% {left: -300%;}
	50%, 65% {left: -400%;}
	75%, 90% {left: -100%;}
}

@-webkit-keyframes slidesStart03 {
	65.01% {left: 0;}
	0%, 15%, 100% {left: -200%;}
	25%, 40% {left: -300%;}
	50%, 65% {left: -400%;}
	75%, 90% {left: -100%;}
}

@keyframes slidesStart103 {
	65.01% {left: 0;}
	0%, 15%, 100% {left: -200%;}
	25%, 40% {left: -300%;}
	50%, 65% {left: -400%;}
	75%, 90% {left: -100%;}
}

@-webkit-keyframes slidesStart103 {
	65.01% {left: 0;}
	0%, 15%, 100% {left: -200%;}
	25%, 40% {left: -300%;}
	50%, 65% {left: -400%;}
	75%, 90% {left: -100%;}
}

@keyframes slidesStart04 {
	40.01% {left: 0;}
	0%, 15%, 100% {left: -300%;}
	25%, 40% {left: -400%;}
	50%, 65% {left: -100%;}
	75%, 90% {left: -200%;}
}

@-webkit-keyframes slidesStart04 {
	40.01% {left: 0;}
	0%, 15%, 100% {left: -300%;}
	25%, 40% {left: -400%;}
	50%, 65% {left: -100%;}
	75%, 90% {left: -200%;}
}

@keyframes slidesStart104 {
	40.01% {left: 0;}
	0%, 15%, 100% {left: -300%;}
	25%, 40% {left: -400%;}
	50%, 65% {left: -100%;}
	75%, 90% {left: -200%;}
}

@-webkit-keyframes slidesStart104 {
	40.01% {left: 0;}
	0%, 15%, 100% {left: -300%;}
	25%, 40% {left: -400%;}
	50%, 65% {left: -100%;}
	75%, 90% {left: -200%;}
}

/* 2. Wechsel des ersten Slides ans Ende und zurück */
@keyframes slide01ToEndStart01 {
	89.99% {left: 0;}
	90%, 100% {left: 100%;}
}

@-webkit-keyframes slide01ToEndStart01 {
	89.99% {left: 0;}
	90%, 100% {left: 100%;}
}

@keyframes slide01ToEndStart101 {
	89.99% {left: 0;}
	90%, 100% {left: 100%;}
}

@-webkit-keyframes slide01ToEndStart101 {
	89.99% {left: 0;}
	90%, 100% {left: 100%;}
}

@keyframes slide01ToEndStart02 {
	49.99%, 90.01% {left: 0;}
	50%, 90% {left: 100%;}
}

@-webkit-keyframes slide01ToEndStart02 {
	49.99%, 90.01% {left: 0;}
	50%, 90% {left: 100%;}
}

@keyframes slide01ToEndStart102 {
	49.99%, 90.01% {left: 0;}
	50%, 90% {left: 100%;}
}

@-webkit-keyframes slide01ToEndStart102 {
	49.99%, 90.01% {left: 0;}
	50%, 90% {left: 100%;}
}

@keyframes slide01ToEndStart03 {
	24.99%, 65.01% {left: 0;}
	25%, 65% {left: 100%;}
}

@-webkit-keyframes slide01ToEndStart03 {
	24.99%, 65.01% {left: 0;}
	25%, 65% {left: 100%;}
}

@keyframes slide01ToEndStart103 {
	24.99%, 65.01% {left: 0;}
	25%, 65% {left: 100%;}
}

@-webkit-keyframes slide01ToEndStart103 {
	24.99%, 65.01% {left: 0;}
	25%, 65% {left: 100%;}
}

@keyframes slide01ToEndStart04 {
	40.01% {left: 0;}
	0%, 40% {left: 100%;}
}

@-webkit-keyframes slide01ToEndStart04 {
	40.01% {left: 0;}
	0%, 40% {left: 100%;}
}

@keyframes slide01ToEndStart104 {
	40.01% {left: 0;}
	0%, 40% {left: 100%;}
}

@-webkit-keyframes slide01ToEndStart104 {
	40.01% {left: 0;}
	0%, 40% {left: 100%;}
}

/* 3. Animationen für den Farbwechsel in den Controls */
@keyframes slideControl01 {
	24.99% {background: #68b022;}
	25%, 100% {background: none;}
}

@-webkit-keyframes slideControl01 {
	24.99% {background: #68b022;}
	25%, 100% {background: none;}
}

@keyframes slideControl101 {
	24.99% {background: #68b022;}
	25%, 100% {background: none;}
}

@-webkit-keyframes slideControl101 {
	24.99% {background: #68b022;}
	25%, 100% {background: none;}
}

@keyframes slideControl02 {
	24.99%, 50% {background: none;}
	25%, 49.99% {background: #68b022;}
}

@-webkit-keyframes slideControl02 {
	24.99%, 50% {background: none;}
	25%, 49.99% {background: #68b022;}
}

@keyframes slideControl102 {
	24.99%, 50% {background: none;}
	25%, 49.99% {background: #68b022;}
}

@-webkit-keyframes slideControl102 {
	24.99%, 50% {background: none;}
	25%, 49.99% {background: #68b022;}
}

@keyframes slideControl03 {
	49.99%, 75% {background: none;}
	50%, 74.99% {background: #68b022;}
}

@-webkit-keyframes slideControl03 {
	49.99%, 75% {background: none;}
	50%, 74.99% {background: #68b022;}
}

@keyframes slideControl103 {
	49.99%, 75% {background: none;}
	50%, 74.99% {background: #68b022;}
}

@-webkit-keyframes slideControl103 {
	49.99%, 75% {background: none;}
	50%, 74.99% {background: #68b022;}
}

@keyframes slideControl04 {
	74.99% {background: none;}
	75%, 100% {background: #68b022;}
}

@-webkit-keyframes slideControl04 {
	74.99% {background: none;}
	75%, 100% {background: #68b022;}
}

@keyframes slideControl104 {
	74.99% {background: none;}
	75%, 100% {background: #68b022;}
}

@-webkit-keyframes slideControl104 {
	74.99% {background: none;}
	75%, 100% {background: #68b022;}
}

/* Basisfunktionalität des Sliders */
.slider {
	overflow: hidden;
}

.slider input {
	position: absolute;
	left: -10000px;
	top: 0;
}

.slideList {
	width: 400%; /* Anzahl der Slides mal 100 */
	position: relative; /* über die relative Positionierung wird der Slider durchs Sichtfenster geschoben */
	-webkit-transition: left 2s;
	-moz-transition: left 2s;
	-o-transition: left 2s;
	transition: left 2s; /* für den fließenden Schub */
	margin: 0;
	padding: 0;
}

.slideList:after {
	content: ".";
	display: block;
	height: .1px;
	clear: both;
	visibility: hidden;
	font-size: 0;
	overflow: hidden;
}

.slide {
	list-style: none;
	width: 25%; /* Breite gleich 100 / Anzahl Slides */
	float: left;
	position: relative;
	left: 0;
	-webkit-transition: left 0s .5s;
	-moz-transition: left 0s .5s;
	-o-transition: left 0s .5s;
	transition: left 0s .5s; /*bei Klick auf ein Control werden alle Slides wieder auf Original-Position geschoben, hier für den ersten relevant. Damit die Aktion erst nach der slides-Verschiebung beginnt, kommt ein delay hinzu*/
}

#slide04:checked ~ .slideList .slide,
#slide104:checked ~ .slideList .slide {
	-webkit-transition-delay: 2s;
	-moz-transition-delay: 2s;
	-o-transition-delay: 2s;
	transition-delay: 2s; /* damit er nicht zu früh zurückrutscht */
}
.slideList img {
	width: 100%;
	height: auto;
	vertical-align: bottom;
}

/* Zuweisung der Keyframe-Animationen */
.slideList,
.slide,
.slideControl label {
	-webkit-animation: 20s 2s infinite;
	animation: 20s 2s infinite; /* allgemeingültige Werte für die Keyframe-Animation */
}

/* Positionierung und Aufruf der passenden Animation in Abhängigkeit des Status der Radiobuttons */
#slide01:checked ~ .slideList {
	-webkit-animation-name: slidesStart01;
	animation-name: slidesStart01;
	left: 0;
}

#slide02:checked ~ .slideList {
	-webkit-animation-name: slidesStart02;
	animation-name: slidesStart02;
	left: -100%;
}

#slide03:checked ~ .slideList {
	-webkit-animation-name: slidesStart03;
	animation-name: slidesStart03;
	left: -200%;
}

#slide04:checked ~ .slideList {
	-webkit-animation-name: slidesStart04;
	animation-name: slidesStart04;
	left: -300%;
}

/* Damit der Wechsel von 01 zu 101, 02 zu 102 usw. klappt, muss jeweils eine andere Animation aufgerufen werden*/
#slide101:checked ~ .slideList {
	-webkit-animation-name: slidesStart101;
	animation-name: slidesStart101;
	left: 0;
}

#slide102:checked ~ .slideList {
	-webkit-animation-name: slidesStart102;
	animation-name: slidesStart102;
	left: -100%;
}

#slide103:checked ~ .slideList {
	-webkit-animation-name: slidesStart103;
	animation-name: slidesStart103;
	left: -200%;
}

#slide104:checked ~ .slideList {
	-webkit-animation-name: slidesStart104;
	animation-name: slidesStart104;
	left: -300%;
}

/* Der erste Slide wird jeweils zur rechten Zeit an den Anfang oder das Ende gestellt */
#slide01:checked ~ .slideList .slide01 {
	-webkit-animation-name: slide01ToEndStart01;
	animation-name: slide01ToEndStart01;
}

#slide02:checked ~ .slideList .slide01 {
	-webkit-animation-name: slide01ToEndStart02;
	animation-name: slide01ToEndStart02;
}

#slide03:checked ~ .slideList .slide01 {
	-webkit-animation-name: slide01ToEndStart03;
	animation-name: slide01ToEndStart03;
}

#slide04:checked ~ .slideList .slide01 {
	-webkit-animation-name: slide01ToEndStart04;
	animation-name: slide01ToEndStart04;
}

/* Separate Animations-Namen für die zweite Steuerung */
#slide101:checked ~ .slideList .slide01 {
	-webkit-animation-name: slide01ToEndStart101;
	animation-name: slide01ToEndStart101;
}

#slide102:checked ~ .slideList .slide01 {
	-webkit-animation-name: slide01ToEndStart102;
	animation-name: slide01ToEndStart102;
}

#slide103:checked ~ .slideList .slide01 {
	-webkit-animation-name: slide01ToEndStart103;
	animation-name: slide01ToEndStart103;
}

#slide104:checked ~ .slideList .slide01 {
	-webkit-animation-name: slide01ToEndStart104;
	animation-name: slide01ToEndStart104;
}

/* nur zur Deko */
.sliderWrapper {
	position: relative;
	padding: 6px;
	border: 1px solid #ddd;
	margin-bottom: 40px;
}

.slide p {
	position: absolute;
	bottom: 1em;
	left: 0;
	background: rgba(0, 0, 0, .6);
	color: #ddd;
	padding: .4em 1em;
}

/* Steuerung durch den Benutzer */
.slideControl {
	width: 80px;
	position: absolute;
	bottom: -40px;
	left: 50%;
	margin-left: -40px;
	padding: 0;
}

.control01:checked ~ .slideControl01,
.control02:checked ~ .slideControl02 {
	left: -5000px; /* Blendet die nicht benötigten Labels aus */
}

.slideControl li {
	float: left;
	margin: 0 4px;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	position: relative;
	text-indent: -10000px;
	border: 1px solid #ccc;
	box-shadow: 0 0 2px 2px #ccc;
	list-style: none;
}

.slideControl label {
	display: block;
	cursor: pointer;
	background: none;
	width: 100%;
	height: 100%;
	border-radius: 50%;
	box-sizing: border-box;
	border: 2px solid #fff;
}

.slideControl label:hover {
	background: #68b022!important;
}

#slide01:checked ~ .slideControl label[for="slide101"],
#slide02:checked ~ .slideControl label[for="slide102"],
#slide03:checked ~ .slideControl label[for="slide103"],
#slide04:checked ~ .slideControl label[for="slide104"] {
	-webkit-animation-name: slideControl01;
	animation-name: slideControl01;
	background: #68b022;
}

#slide101:checked ~ .slideControl label[for="slide01"],
#slide102:checked ~ .slideControl label[for="slide02"],
#slide103:checked ~ .slideControl label[for="slide03"],
#slide104:checked ~ .slideControl label[for="slide04"]  {
	-webkit-animation-name: slideControl101;
	animation-name: slideControl101;
	background: #68b022;
}

#slide01:checked ~ .slideControl label[for="slide102"],
#slide02:checked ~ .slideControl label[for="slide103"],
#slide03:checked ~ .slideControl label[for="slide104"],
#slide04:checked ~ .slideControl label[for="slide101"] {
	-webkit-animation-name: slideControl02;
	animation-name: slideControl02;
}

#slide101:checked ~ .slideControl label[for="slide02"],
#slide102:checked ~ .slideControl label[for="slide03"],
#slide103:checked ~ .slideControl label[for="slide04"],
#slide104:checked ~ .slideControl label[for="slide01"]  {
	-webkit-animation-name: slideControl102;
	animation-name: slideControl102;
}

#slide01:checked ~ .slideControl label[for="slide103"],
#slide02:checked ~ .slideControl label[for="slide104"],
#slide03:checked ~ .slideControl label[for="slide101"],
#slide04:checked ~ .slideControl label[for="slide102"]  {
	-webkit-animation-name: slideControl03;
	animation-name: slideControl03;
}

#slide101:checked ~ .slideControl label[for="slide03"],
#slide102:checked ~ .slideControl label[for="slide04"],
#slide103:checked ~ .slideControl label[for="slide01"],
#slide104:checked ~ .slideControl label[for="slide02"]  {
	-webkit-animation-name: slideControl103;
	animation-name: slideControl103;
}

#slide01:checked ~ .slideControl label[for="slide104"],
#slide02:checked ~ .slideControl label[for="slide101"],
#slide03:checked ~ .slideControl label[for="slide102"],
#slide04:checked ~ .slideControl label[for="slide103"] {
	-webkit-animation-name: slideControl04;
	animation-name: slideControl04;
}

#slide101:checked ~ .slideControl label[for="slide04"],
#slide102:checked ~ .slideControl label[for="slide01"],
#slide103:checked ~ .slideControl label[for="slide02"],
#slide104:checked ~ .slideControl label[for="slide03"]  {
	-webkit-animation-name: slideControl104;
	animation-name: slideControl104;
}
  • Kegelschnitte

  • Maßaufgaben

    Maßaufgaben

  • Würfelkomposition

    Würfelkomposition

  • Schnitt Zylinder - Hyperboloid

    Schnittkurve von Zylinder und Hyperboloid