10.9.12
3D Galerie ohne Javascript
Könnt ihr euch an die endlosen Stunden im Matheunterricht erinnern, wo ihr euch mit Tangenten, Matrizen und Vektoren rumgequält habt? Habt ihr euch je gefragt, zu was das wohl nützlich sei?Heute die Antwort: Das braucht ihr, um coole 3D-Galerien zu bauen - schaut euch die Demo an, öffnet die Galerie mit Click auf den goldenen Layer.
Vorbemerkung
Mir ist klar, dass es anspruchsvoll ist, 3D Modelle zu bauen. Im Webdesign spielt 3D auch [noch] keine große Rolle - dafür war bis vor kurzem die Browserunterstützung einfach zu schlecht.Inzwischen können alle Browser 3D, sogar der Internet Explorer ab 9+. Man kann 3D also bedenkenlos zumindest für dekorative Sachen einsetzen ... wenn man es beherrscht. Die Technik dahinter ist allerdings viel schwieriger in den Griff zu bekommen als 2D - zumindest geht mir das so.
Die Skizze hier ist es so etwas wie 'ein-erstes-nachdenken-über-3D'. Ich mag ja immer andere dazu motivieren, sich tiefer mit CSS zu beschäftigen und da ist 3D meiner Ansicht nach ein wahnsinnig spannendes Feld - einfach weil es da bisher sehr wenig gibt.
Diese 3D Gallerie hat mich alles zusammen knapp drei Wochen beschäftig ... und ist noch nicht mal besonders 'spektakulär'. Aber das Sahnehäubchen bekommt nur wer seinen Grießbrei schön fleissig löffelt, oder?
Let's rock: HTML
Ich erkläre die Skizze Schritt für Schritt - starten wir mit dem HTML.Mittlerweile habe ich das ja schon mehrmals verwendet - zum vorwärts und rückwärts 'rollen' benütze ich einen Schalter mit
input type="radio" Elementen.Nehmen wir also zuerst neun
input Element: Warum ich das in umgekehrter Reihenfolge schreibe, erkläre ich gleich.
<input id="box9" name="nav" type="radio" />
<input id="box8" name="nav" type="radio" />
<input id="box7" name="nav" type="radio" />
<input id="box6" name="nav" type="radio" />
<input id="box5" name="nav" type="radio" />
<input id="box4" name="nav" type="radio" />
<input id="box3" name="nav" type="radio" />
<input id="box2" name="nav" type="radio" />
<input id="box1" name="nav" type="radio" />
Unterhalb der neun
input Elemente liegen die neun dazugehörigen label Elemente - innerhalb der Label liegen die img Tags. Alles zusammen wrapper ich in einem 'Rahmen', dem holder. Das letzte Label wird das 'Deckblatt' für die Galerie - im 2D Ausgangszustand liegen alle Labels übereinander und das 'neunte' Blatt ist bei der Animation sozusagen das 'erste' Blatt ... deshalb das ganze in genau umgekehrter Reihenfolge.
<div class="holder">
<input id="box9" name="nav" type="radio" />
<input id="box8" name="nav" type="radio" />
<input id="box7" name="nav" type="radio" />
<input id="box6" name="nav" type="radio" />
<input id="box5" name="nav" type="radio" />
<input id="box4" name="nav" type="radio" />
<input id="box3" name="nav" type="radio" />
<input id="box2" name="nav" type="radio" />
<input id="box1" name="nav" type="radio" />
<div id="carousel">
<label for="box9"><img src="http://goo.gl/cbB1B"/></label>
<label for="box8"><img src="http://goo.gl/vdJud"/></label>
<label for="box7"><img src="http://goo.gl/Ot1nv"/></label>
<label for="box6"><img src="http://goo.gl/NYJyu"/></label>
<label for="box5"><img src="http://goo.gl/uX7NY"/></label>
<label for="box4"><img src="http://goo.gl/f8o7t"/></label>
<label for="box3"><img src="http://goo.gl/Z979b"/></label>
<label for="box2"><img src="http://goo.gl/wTB34"/></label>
<label for="box1">Russische Ikonen</label>
</div>
</div>
An HTML wäre das ansonsten alles - ziemlich simpel, oder?
3D - kurze Vorüberlegung
Denkt mal an euren Zeichenunterricht zurück - eine dreidimensionale Perspektive braucht einen Standpunkt und einen Fluchtpunkt eines fiktive Beobachter, d.h. je nachdem, von wo ihr ein Objekt betrachtet, sieht es stark unterschiedlich aus, logisch oder?Außerdem braucht jede dreidimensionale Darstellung eine Breite, eine Höhe und eine Tiefe. In mathematischer Sprache ist das die x-Achse, y-Achse und z-Achse.
CSS: Grundlage
Um das auf unsere Gallerie anzuwenden, geben wir zunächst dem 'Rahmen' - d.h. demholder - eine perspective von 1000px - das wird der 'Abstand' des fiktiven Beobachters von der Gallerie.Der Fluchtpunkt liegt in dem Fall - falls wir es nicht anders angeben - genau in der Mitte des 'Rahmens'.
In dem Rahmen liegt das 'Karussell' - das machen wir mit
.holder {
width: 199px;
height: 299px;
position: absolute;
left: 50%;
perspective: 1000px;
}
preserve-3d fit für 3D, sprich, damit lassen sich die Elemente auch auf der Z-Achse (der Raumtiefe) transformieren.Mit
translateZ versetzen wir das 'Karussell'um 288px nach hinten - das gibt den 'Öffnungseffekt' beim anklicken des goldenen Layers. Zuletzt noch die Labels mit den img Tags - die bekommen a bisserl 2D Grundstyling:
#carousel {
width: 100%;
height: 100%;
position: absolute;
transform: translateZ( -288px );
transform-style: preserve-3d;
transition: transform 1s;
}
Das 'neunte' Element, d.h. das Deckblatt wird gesondert behandelt:
#carousel label {
display: block;
position: absolute;
width: 200px;
height: 300px;
line-height: 300px;
font-size: 20px;
font-weight: bold;
text-align: center;
}
So weit so gut. Wenn ihr jetzt die Galerie anschaut, seht ihr im Grunde nur das 'Deckblatt' - alle anderen Blätter liegen darunter. Nicht besonders spektakulär, oder?
#carousel label:nth-child(9) { background: gold; color: #111 }
CSS: 3D Styling
Immer gut, wenn man sich ab und zu vor Augen hält, was man eigentlich will: Wir wollen eine 'Karussell' mit insgesamt neun Elementen. Dieses 'Karussell' soll sich auf der y-Achse bewegen, auf der x-Achse dagegen nicht.y-Achse
Jedes dieser neun Elemente ist also auf einer Kreisbahn der y-Achse angeordnet. Ein ganzer Kreis hat einen Winkel von 360° - das geteilt durch neun ergibt 40°. Jedes Element steht zum nächsten Element also um 40° verschoben.z-Achse
Die 'Raumtiefe', d.h. der Abstand der einzelnen Bilder zum Kreismittelpunkt bleibt immer gleich. Der Abstand lässt sich nun entweder pi mal Daumen und try und error bestimmen, oder ihr berechnet es.Ich könnte es ausführlicher erklären oder ihr glaubt mir das, gesuchte Abstand r zum Kreismittelpunkt ist: r=(breite/2)/tan(20)
Dabei ist 'breite' die Breite eines einzelnen Elements. Bezogen auf unser Beispiel wäre der Abstand (bei einem perfektem geschlossenem Kreis) zum Kreismittelpunkt also 274px.
Beispiel
Damit das alles nicht so abstrakt bleibt, hier das Beispiel für die ersten drei Elemente:Das erste Element hat auf der y-Achse gar keine Verschiebung, das zweite Element zum ersten Element eine Verschiebung um 40° und so weiter.
#carousel label:nth-child(1) {
transform: rotateY( 0deg ) translateZ( 274px );
}
#carousel label:nth-child(2) {
transform: rotateY( 40deg ) translateZ( 274px );
}
#carousel label:nth-child(3) {
transform: rotateY( 80deg ) translateZ( 274px );
}
...
Die 'Raumtiefe', d.h. der Abstand zum Kreismittelpunkt bleibt immer gleich, nämlich 274px. Das ganze könnt ihr jetzt schreiben und ihr habt ein 'statisches' Karussel - nicht schlecht, aber noch immer nicht, was wir eigentlich wollen. Wie kriegen wir das ganze jetzt beweglich?
3D Bewegung
Um zu sehen, wie die Elemente bewegt werden, schauen wir uns das erste Element im Ausgangszustand an - das Element steht auf der y-Achse bei 0°.Mit klick auf das erste Element verschieben wir es nun um 40°:
#carousel label:nth-child(1) {
transform: rotateY( 0deg ) translateZ( 274px );
}
Damit das ganze schön 'smooth' passiert, legen wir eine transition drauf:
#box1:checked ~ #carousel label:nth-child(1) {
transform: rotateY( 40deg ) translateZ( 310px );
}
Und fertig ist die Bewegung - der Rest ist nur noch Fleißarbeit:=).
input:checked ~ #carousel label{
transition: all 1s
}
Mit Click auf das zweite Label würde sich etwa das erste Element um 80° verschieben:
und so weiter ... schaut es euch an. Wenn ihr einmal das dahinter liegende Prinzipe verstanden habt, ist es nicht mehr besonders kompliziert.
#box2:checked ~ #carousel label:nth-child(1) {
transform: rotateY( 80deg ) translateZ( 310px );
}
Transparenz-Effekt
In der Gallerie hat nur das jeweils oberste Bild eine Deckkraft von 100% - alle anderen Bildern sind transparent - ich benütze dazu die sehr nützliche Eigenschaftnot. Alle Bilder außer dem angeklickten Bild bekommen damit die Transparenz ".1".
#box9:checked ~ #carousel label:not(:nth-child(1)) {
opacity: .1
}
#box8:checked ~ #carousel label:not(:nth-child(2)) {
opacity: .1
}
#box7:checked ~ #carousel label:not(:nth-child(3)) {
opacity: .1
}
#box6:checked ~ #carousel label:not(:nth-child(4)) {
opacity: .1
}
#box5:checked ~ #carousel label:not(:nth-child(5)) {
opacity: .1
}
#box4:checked ~ #carousel label:not(:nth-child(6)) {
opacity: .1
}
#box3:checked ~ #carousel label:not(:nth-child(7)) {
opacity: .1
}
#box2:checked ~ #carousel label:not(:nth-child(8)) {
opacity: .1
}
#box1:checked ~ #carousel label:not(:nth-child(9)) {
opacity: .1
}
Zusammenfassung
Das ist relativ harter Stoff - nix mal für so zwischendurch zum ausprobieren :=). Man muss sich einarbeiten, viel rumprobieren und vor allem selber machen, selber machen, selber machen.Ich kann hier nur ein paar allgemeine Hinweise geben - eher grobe Brocken, nichts 'mundgerechtes'. Ich hoffe, das ist mal für jemand vom Nutzen ...