search check home clock-o tag tags chevron-left chevron-right chevron-up chevron-down twitter facebook github rss comment comments terminal code

[CSS][JS] Jak utworzyć animowane trójwymiarowe obiekty w CSS?

[CSS][JS] Jak utworzyć animowane trójwymiarowe obiekty w CSS?

Do tej pory, animacje 3D kojarzyły się najczęściej z grami komputerowymi lub filmami. Do ich utworzenia wykorzystywano zupełnie inne języki programowania niż CSS czy JS. Na szczęście, obecny postęp technologiczny i rozwoju języków webowych pozwala na utworzenie obiektów 3D czy animacji 3D już za pomocą CSS.

Co ciekawe, wykorzystanie CSS sprawia, że wykorzystujemy moc karty graficznej, czyli nie potrzebujemy dodatkowego oprogramowania, które będzie odpowiedzialne za generowanie efektów, tak jak np. ma to miejsce we Flashu.

W tym wpisie zostanie omówiony sposób uzyskania trójwymiarowego sześcianu (kostki), a następnie animowania jej w oknie przeglądarki.

Szkielet sześcianu w HTML

Aby zbudować strukturę HTML dla sześcianu potrzebujemy 7 elementów: kontenera na kostkę i 6 ścian. Kod HTML, który spełnia te założenia wygląda następująco:

1
2
3
4
5
6
7
8
  <div class="cube">
    <div class="top"></div>
    <div class="right"></div>
    <div class="bottom"></div>
    <div class="left"></div>
    <div class="front"></div>
    <div class="back"></div>
  </div>

Zdefiniowano kontener dla kostki (.cube), a wewnątrz niego dodano 6 divów, które będą pełniły rolę ścian.

Wygląd sześcianu w CSS3

Tak przygotowaną strukturę HTML należy ostylować, tak aby zaczęło to wszystko przypominać kostkę sześcienna. Wykorzystamy tu kilka właściwości CSS, które potrzebują prefiksów, aby działały w większej liczbie przeglądarek internetowych. Dla zwiększenia czytelności, przykłady będę omawiał na wartościach bez prefiksów.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
.cube {
  display: block;
  position: relative;
  width: 108px;
  height: 108px;
  margin: 0 31px;
  float: left;
  transform-style: preserve-3d; /* --- prefix --- */
  transition: all 1.5s ease 0s; /* --- prefix --- */
}
.cube > div {
  background-size: cover;
  height: 100%;
  overflow: hidden;
  position: absolute;
  width: 100%;
  opacity: 0.9;
}
.cube .front {
  background: url('logo.png') no-repeat;
  transform: rotate3d(0, 1, 0, 0deg) translate3d(0, 0, 54px);   /* --- prefix --- */
}
.cube .back {
  background: #bb3300;
  transform: rotate3d(1, 0, 0, 180deg) translate3d(0, 0, 54px); /* --- prefix --- */
}
.cube .top {
  background: #f04100;
  transform: rotate3d(1, 0, 0, 90deg) translate3d(0, 0, 54px);  /* --- prefix --- */
}
.cube .right {
  background: #222;
  transform: rotate3d(0, 1, 0, 90deg) translate3d(0, 0, 54px);  /* --- prefix --- */
}
.cube .bottom {
  background: #f04100;
  transform: rotate3d(1, 0, 0, -90deg) translate3d(0, 0, 54px); /* --- prefix --- */
}
.cube .left {
  background: #222;
  transform: rotate3d(0, 1, 0, -90deg) translate3d(0, 0, 54px); /* --- prefix --- */
}

Klasa cube jest kontenerem dla ścianek kostki. W niej ustawiono 2 ciekawe własności: transform-style oraz transition. Pierwsza z nich jest odpowiedzialna za zdefiniowanie stylu przeprowadzanych transformacji na strukturze HTML, a druga z nich jest odpowiedzialna za tworzenie animacji przejścia między stanami obiektu (w tym przypadku, sprawdza wszystkie własności i animuje zmiany między ich wartościami).

Wewnątrz kostki zdefiniowano ścianki i każda z nich ma określony kolor oraz położenie względem osi XYZ. Własność transform przyjmuje dwie wartości w postaci funkcji: rotate3d oraz translate3d.
Funkcja rotate3d jest odpowiedzialna za "okręcenie" elementu względem osi XYZ, natomiast funkcja translate3d odpowiada za przesunięcie elementu w głębi.

Animowanie kostki za pomocą JS

Aby tak przygotowany element strony nabrał życia należy utworzyć skrypt, który będzie powodował animację między właściwościami elementu. Taki skrypt, napisany w JS, może wyglądać następująco:

$(function() {
  // znajdź wszystkie elementy z klasą cube
  var cubes       = $('.cube');
  // nazwa właściwości CSS, której wartości będziemy zmieniać
  var propertyName= 'transform';
  // prefiksy dla różnych wersji przeglądarek
  var prefix      = ['-webkit-', '-moz-', '-o-', '-ms-', ''];
 
  // uruchamiamy pętlę czasową, która trwa 1,4 sek.
  setInterval(function() {
 
    //dla każdego elementu/kostki
    cubes.each(function() {
      // oblicz wartości przesunięcia względem osi, kolejno: OX, OY, OZ oraz margines górny
      var rotateX   = parseInt(Math.floor(Math.random() * (720 - 1 + 1)) + 1, 10) + 'deg';
      var rotateY   = parseInt(Math.floor(Math.random() * (720 - 1 + 1)) + 1, 10) + 'deg';
      var rotateZ   = parseInt(Math.floor(Math.random() * (720 - 1 + 1)) + 1, 10) + 'deg';
      var marginTop = parseInt(Math.floor(Math.random() * (432 - 1 + 1)) + 1, 10) + 'px';
 
      // obiekt, ktory będzie zawierał nowe właściwości
      var properties = {'margin-top' : marginTop};
 
      // utwórz właściwość CSS sprefiksowaną, dzięki temu większa liczba przeglądarek będzie w stanie obsłużyć animację
      $.each(prefix, function(i, k) {
        properties[k + propertyName] = 'rotateY(' + rotateY + ') rotateX(' + rotateX + ') rotateZ(' + rotateZ + ')';
      });
 
      // przypisz nowo utworzonoe właściwości do obiektu
      $(this).css(properties);
 
    });
  }, 1400);

Każdą animację odpalamy co 1.4 sekundy. Jeśli dobrze się przypatrzysz, to w CSS zdefiniowaliśmy czas trwania animacji na 1.5 sekundy. Krótszy czas interwału zdefiniowanego w JS pozwoli na zachowanie płynności między kolejnymi stanami.

Powyższy kod JS został opisany komentarzami.

Podsumowanie informacji o animacjach 3D w CSS

Powyższy przykład kodu HTML, CSS i JS ma za zadanie uświadomić Ciebie, że tworzenie animacji 3D nie jest trudne. Jedynym ograniczeniem może być wsparcie przeglądarek.

Przeglądarka wsparcie
Mozilla Firefox tak
Google Chrome tak
Opera nie
Safari tak
Internet Explorer

7/8/9/10

nie

Jeśli jednak wsparcie dla przeglądarek nie jest najważniejszym czynnikiem użyteczności danego rozwiązania, to nic nie stoi na przeszkodzie aby dać ponieść się swojej kreatywności i stworzyć coś naprawdę ciekawego, niespotykanego.

Demo z tego artykułu możesz zobaczyć pod tym linkiem: animacje 3D w CSS

  • Comandeer

    setInterval to chyba najgorszy wybór do takiego typu animacji 😉 zwłaszcza, że wsparcie dla requestAnimationFrame jest na tyle duże, że można go z powodzeniem użyć jedynie z fallbackiem do setInterval
    a co do HTML – myślę nad zastosowaniem czegoś, co na razie leży jako draft w W3C: ShadowDOM. dzięki temu moglibyśmy mieć jeden element (np cube) i na nim operować. no ale to już zupełnie inna bajka 😉

  • @up – Mozesz podac jakis JASNY tutorial dla requestAnimationFrame?

  • Kiedyś pracowałem z requestAnimationFrame. W najbliższym czasie postaram się przygotować jakiś wpis na ten temat.

  • Comandeer

    @procek nie bardzo, jedynie mogę polecić krótki opis na MDN – to jedyny w miarę jasny. reszta to żmudne eksperymenty w domowym zaciszu 😉

  • Niestety, ostatnio cierpię na brak czasu. Tutaj można znaleźć dobry opis tej technologii: źródło

  • Dawid

    Ostatnio zauważyłem, że w najnowszej wersji Chrome (31) kostka nie działa tak jak należy – widać tylko przednią ściankę. Reszta po prostu się nie wyświetla. Próbowałem znaleźć źródło tego problemu, niestety bezskutecznie. W Chrome Canary (33) wszystko działa poprawnie. Czy wie ktoś, jaka może być tego przyczyna?

  • Właśnie sprawdziłem na wersji 31 Chrome’a i działa jak należy. Jeśli byłbyś w stanie dostarczyć jakiś screenshot lub filmik przedstawiający ten problem to możnaby było to lepiej sprawdzić.

  • Dawid

    Tak to wygląda – http://fotodyl.pl/ab2a78ee62/

    Oczywiście obiekty animują się, tylko nie widać pozostałych ścian.