CSS3 - Animowany sześcian 3D

W tej części kursu CSS z elementów HTML utworzymy animowany sześcian.

Końcowy efekt został zaprezentowany poniżej.

Sześcian to nic innego jak bryła geometryczna, która składa się z sześciu ścian. Każda z tych ścian jest kwadratem. Oczywiście do utworzenia naszego sześcianu wykorzystamy wyłącznie język HTML oraz CSS, co dla niektórych może wydawać się rzeczą nieprawdopodobną :)

Wbrew pozorom utworzenie układu elementów HTML, który został zaprezentowany powyżej, nie jest niczym trudnym, jednak musimy sobie uświadomić kilka rzeczy, które dotyczą przekształceń w przestrzeni perspektywy.

Bez wątpienia, aby utworzyć nasz docelowy układ elementów HTML będziemy potrzebowali sześciu elementów HTML, tych samych rozmiarów, które zostaną umieszczone w innym elemencie HTML, dla którego zostanie określona przestrzeń perspektywy. Całość umieścimy w kolejnym dodatkowym elemencie HTML.

Tworzymy następujący układ elementów HTML.

<body>

  <div id="perspektywa">
    <div id="rodzic">
      <div id="przod"></div>
      <div id="tyl"></div>
      <div id="lewo"></div>
      <div id="prawo"></div>
      <div id="gora"></div>
      <div id="dol"></div>
    </div>
  </div>

</body>

Dla elementu #perspektywa oraz dla wszystkich jego potomków określamy te same rozmiary szerokości oraz wysokości, dodatkowo do wszystkich dzieci elementu #rodzic dodajemy właściwość position:absolute; dzięki czemu wszystkie elementy dzieci znajdą się w tym samym miejscu, jeden na drugim, w obszarze elementu #rodzic. Dla elementu #rodzic określamy właściwość position:relative; dzięki czemu elementy z właściwością position:absolute; będą pozycjonowane względem jego (co już powinniśmy wiedzieć z poprzednich części tego kursu CSS).

#perspektywa {
  width:100px;
  height:100px;
  margin:0 auto;
}

#rodzic {
  width:100%;
  height:100%;
  position:relative;
}

#rodzic > div {
  width:100%;
  height:100%;
  position:absolute;
}

Rezultat:

Oczywiście naszym oczom nie ukazało się nic co moglibyśmy zauważyć, ponieważ nasze elementy HTML nie zawierają w sobie żadnej zawartości, koloru obramowania, czy też koloru tła, jednak wszystko idzie zgodnie z naszym planem.

Gdy dodamy przestrzeń perspektywy za pomocą właściwości perspective:300px; do elementu #perspektywa to zostanie utworzona przestrzeń perspektywy o podanej wartości, dla elementów dzieci elementu #parspektywa, a tymi elementami w tym wypadku jest tylko jeden element HTML, czyli element #rodzic.

We wspomnianej przestrzeni perspektywy znajdzie się tylko element #rodzic, ponieważ właśnie w ten sposób działa właściwość perspective (przestrzeń perspektywy nie jest tworzona dla elementu HTML, do którego jest dodawana właściwość perspective).

Dodatkowo do elementu #rodzic musimy dodać właściwość transform-style:preserve-3d; dzięki czemu jego elementy dzieci znajdą się w tej samej perspektywie, w której znajduje się element #rodzic.

#perspektywa {
  width:100px;
  height:100px;
  margin:0 auto;
  perspective:300px;
}

#rodzic {
  width:100%;
  height:100%;
  position:relative;
  transform-style:preserve-3d;
}

W momencie utworzenia przestrzeni perspektywy, w elemencie HTML, do którego została dodana właściwość perspective, tworzy się punkt zwany punktem środka perspektywy. Punkt ten został przeze mnie zaznaczony czarnym kolorem. Między innymi względem tego punktu są dokonywana przekształcenia na elementach HTML, które znajdą się w przestrzeni perspektywy, w której znajduje się dany punkt środka perspektywy.

Na chwilę dodamy kolorowe tło, do każdego z dzieci elementu #rodzic, dzięki czemu zobaczymy rozmiary danego dziecka.

Zobaczmy co się stanie z każdym z dzieci elementu #rodzic, gdy przekształcimy je za pomocą funkcji translateZ(), która zmienia miejsce elementu HTML w przestrzeni perspektywy, wzdłuż prostopadłej osi Z elementu HTML.

Tak więc dodajemy, na chwilę, właściwość transform wraz z funkcją translateZ() do każdego z dzieci elementu #rodzic, używając różnego parametru funkcji translateZ(), np. 20px, 40px, 60px, 80px, 100px, 120px.

Każde dziecko elementu #rodzic zostało odsunięte od swojej pozycji początkowej w przestrzeni perspektywy, wzdłuż swojej osi Z, o taką wartość jaka znalazła się w funkcji translateZ(). Żeby lepiej to zauważyć obrócimy, na chwilę, nasz układ elementów HTML względem osi Y elementu #rodzic.

Jeżeli chcemy, aby element HTML był przesuwany w innym kierunku, za pomocą funkcji translateZ(), w przestrzeni perspektywy, to interesujący nas element HTML musimy pierw obrócić o jakąś ilość stopni względem jego osi X lub osi Y, w zależności, w którą chcemy stronę chcemy obrócić oraz przesunąć dany element HTML.

W przykładzie, który został zaprezentowany poniżej, dzieci elementu #rodzic zostały przesunięte o te same wartości wzdłuż osi Z co w poprzednim przykładzie, lecz tym razem co drugie dziecko zostało przesunięte w inną stronę przestrzeni perspektywy, ponieważ do danego dziecka pierw została dodana funkcja rotateY(-45deg).

Poprzednie akapity miały na celu uzmysłowić nam, w jaki sposób możemy sterować kierunkiem przesunięcia elementu HTML w przestrzeni perspektywy, ponieważ informacje te wykorzystamy w tym momencie do utworzenia naszego docelowego sześcianu.

Wracamy do naszego wcześniejszego układu elementów HTML.

Wszystkie dzieci elementu #rodzic, które za chwilę zbudują nasz docelowy sześcian, znajdują się w tym samym miejscu, jeden drugim, mają ten sam rozmiar szerokości i wysokości, czyli 100px × 100px.

Pierw zajmiemy się lewą oraz prawą stroną naszego sześcianu.

Do elementu #lewo dodajemy właściwość transform wraz z funkcjami rotateY(-90deg) translateZ(50px), dzięki czemu element pierw zostanie obrócony względem swojej osi Y o 90 stopni w lewo, a następnie zostanie odsunięty w przestrzeni perspektywy o 50px wzdłuż osi Z.

Do elementu #prawo dodajemy właściwość transform wraz z funkcjami rotateY(90deg) translateZ(50px), dzięki czemu element pierw zostanie obrócony względem swojej osi Y o 90 stopni w prawo, a następnie zostanie odsunięty w przestrzeni perspektywy o 50px wzdłuż osi Z.

Rezultat:

Dokładnie te same czynności wykonujemy dla elementów #gora oraz #dol, lecz zamiast funkcji rotateY() należy podać funkcję rotateX(), dzięki czemu nasze elementy zostaną obrócony względem ich osi X i przesunięte w pionie wzdłuż osi Z.

Rezultat:

Następnie dodajemy właściwość transform:translateZ(50px); do elementu #przod oraz właściwość transform:translateZ(-50px); do elementu #tyl. Nie musimy ich obracać, ponieważ wspomniane elementy HTML mają utworzyć przednią oraz tylną stronę naszego sześcianu, a więc wystarczy, że przesuniemy je wzdłuż osi Z o podane wartości, w głąb przestrzeni perspektywy oraz bardziej do naszego wzroku.

Rezultat:

Pełny zapis właściwości CSS dla poszczególnych części naszego sześcianu został przedstawiony poniżej.

#przod {
  transform:translateZ(50px);
}

#tyl {
  transform:translateZ(-50px);
}

#lewo {
  transform:rotateY(-90deg) translateZ(50px);
}

#prawo {
  transform:rotateY(90deg) translateZ(50px);
}

#gora {
  transform:rotateX(-90deg) translateZ(50px);
}

#dol {
  transform:rotateX(90deg) translateZ(50px);
}

Wartością funkcji translateZ() jest wartość 50px, ponieważ wszystkie elementy HTML w naszym układzie mają ten sam rozmiar 100 × 100, dlatego musieliśmy je odsunąć od pozycji początkowej o 50px w każdą stronę przestrzeni perspektywy, dlatego wszystkie wspomniane elementy HTML idealnie się stykają, ponieważ odległość między nimi wynosi 100px, ponieważ suma odsunięcia każdej pary przeciwnych, stronami do siebie, elementów HTML wynosi 50px + 50px = 100px.

Czas utworzyć animację, która będzie obracała naszym sześcianem.

@keyframes obrot
{
  0% { transform:rotateX(0) rotateZ(0); }
  100% { transform:rotateX(360deg) rotateZ(360deg); }
}

Animacja obrot będzie obracać elementem #rodzic oraz wszystkimi jego dziećmi. Obrót będzie dokonywał się jednocześnie wokół osi X oraz osi Z elementu #rodzic.

#rodzic {
  width:100%;
  height:100%;
  position:relative;
  transform-style:preserve-3d;
  animation:obrot 4s linear infinite;
}

Rezultat:

W przykładzie, który został zaprezentowany powyżej, dla ułatwienia tło elementu #rodzic, na którym to elemencie dokonuje się animacja obrot, zostało zaznaczone kolorem czerwonym.

Dla wszystkich dzieci elementu #rodzic możemy określić takie samo tło oraz ten sam cień.

#rodzic > div {
  width:100%;
  height:100%;
  position:absolute;
  background-image:radial-gradient(ellipse at center,rgba(0,0,255,0.8),rgba(0,0,0,0.8));
  box-shadow:0 0 4px #00F;
}

Rezultat:

Czas utworzyć kropki na naszym sześcianie, dzięki czemu będzie on przypominał kostkę do gry. Utworzenie kropek jest najmniej problematyczną rzeczą w tym układzie elementów HTML. Wystarczy, że dodamy dodatkowe elementy div do każdego dziecka elementu #rodzic, w takiej ilości, aby utworzyły odpowiednią liczbę kropek w danym elemencie HTML, który tworzy daną ścianę naszego sześcianu.

<body>

  <div id="perspektywa">
    <div id="rodzic">
      <div id="przod"></div>
      <div id="tyl"></div>
      <div id="lewo"></div>

      <div id="prawo">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
      </div>

      <div id="gora"></div>
      <div id="dol"></div>
    </div>
  </div>

</body>

Za pół okrągły kształt danego elementu HTML będzie odpowiadała właściwość border-radius:25%; która służy do zaokrąglania widocznych rogów elementu HTML. Nasze elementy div w każdym dziecku elementu #rodzic będą pozycjonowane absolutnie, dzięki właściwości position:absolute; dlatego ich pozycję będziemy mogli kontrolować za pomocą takich właściwości CSS jak: top, right, bottom, left. Ich pozycja będzie liczona względem ich rodzica, ponieważ każde dziecko elementu #rodzic jest pozycjonowane absolutnie, dzięki właściwości position:absolute; którą dodaliśmy przedtem.

Dla poszczególnych elementów, które będą stanowiły pół okrągłe kropki na ścianach sześcianu, będziemy musieli utworzyć osobne reguły CSS, jednak nie musimy dla nich tworzyć żadnych dodatkowych atrybutów id czy class, wystarczy że skorzystamy z selektora :nth-child(), który wskazuje ten numer dziecka elementu HTML, który podamy w selektorze :nth-child().

#rodzic > div > div {
  position:absolute;
  width:20px;
  height:20px;
  background-color:#FFF;
  border-radius:25%;
  box-shadow:0 0 4px 2px #000, 0 0 3px 1px #00F inset;
}

#prawo > div:nth-child(1) {
  left:10px;
  top:10px;
}

#prawo > div:nth-child(2) {
  left:70px;
  top:10px;
}

#prawo > div:nth-child(3) {
  left:70px;
  bottom:10px;
}

#prawo > div:nth-child(4) {
  left:10px;
  bottom:10px;
}

Rezultat:

Reguły CSS dla pozostałych kropek na ścianach sześcianu zostały podane w kodzie dokumentu HTML, który znajduje się poniżej:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Darmowy Kurs CSS</title>

    <style>
      #perspektywa {
        width:100px;
        height:100px;
        margin:0 auto;
        perspective:300px;
        -webkit-perspective:300px;
      }

      #rodzic {
        width:100%;
        height:100%;
        position:relative;
        transform-style:preserve-3d;
        -webkit-transform-style:preserve-3d;
        animation:obrot 4s linear infinite;
        -webkit-animation:obrot 4s linear infinite;
      }

      #rodzic > div {
        width:100%;
        height:100%;
        position:absolute;
        background-image:radial-gradient(ellipse at center,rgba(0,0,255,0.8),rgba(0,0,0,0.8));
        box-shadow:0 0 4px #00F;
      }

      #przod {
        transform:translateZ(50px);
        -webkit-transform:translateZ(50px);
      }

      #tyl {
        transform:translateZ(-50px);
        -webkit-transform:translateZ(-50px);
      }

      #lewo {
        transform:rotateY(-90deg) translateZ(50px);
        -webkit-transform:rotateY(-90deg) translateZ(50px);
      }

      #prawo {
        transform:rotateY(90deg) translateZ(50px);
        -webkit-transform:rotateY(90deg) translateZ(50px);
      }

      #gora {
        transform:rotateX(-90deg) translateZ(50px);
        -webkit-transform:rotateX(-90deg) translateZ(50px);
      }

      #dol {
        transform:rotateX(90deg) translateZ(50px);
        -webkit-transform:rotateX(90deg) translateZ(50px);
      }

      #rodzic > div > div {
        position:absolute;
        width:20px;
        height:20px;
        background-color:#FFF;
        border-radius:25%;
        box-shadow:0 0 4px 2px #000, 0 0 3px 1px #00F inset;
      }

      #przod > div:nth-child(1) { left:40px; top:40px; }

      #tyl > div:nth-child(1) { left:10px; top:10px; }
      #tyl > div:nth-child(2) { left:70px; bottom:10px; }

      #lewo > div:nth-child(1) { left:10px; top:10px; }
      #lewo > div:nth-child(2) { left:40px; top:40px; }
      #lewo > div:nth-child(3) { left:70px; bottom:10px; }

      #prawo > div:nth-child(1) { left:10px; top:10px; }
      #prawo > div:nth-child(2) { left:70px; top:10px; }
      #prawo > div:nth-child(3) { left:70px; bottom:10px; }
      #prawo > div:nth-child(4) { left:10px; bottom:10px; }

      #gora > div:nth-child(1) { left:10px; top:10px; }
      #gora > div:nth-child(2) { left:70px; top:10px; }
      #gora > div:nth-child(3) { left:70px; bottom:10px; }
      #gora > div:nth-child(4) { left:10px; bottom:10px; }
      #gora > div:nth-child(5) { left:40px; top:40px; }

      #dol > div:nth-child(1) { left:10px; top:10px; }
      #dol > div:nth-child(2) { left:70px; top:10px; }
      #dol > div:nth-child(3) { left:10px; top:40px; }
      #dol > div:nth-child(4) { left:70px; top:40px; }
      #dol > div:nth-child(5) { left:70px; bottom:10px; }
      #dol > div:nth-child(6) { left:10px; bottom:10px; }

      @keyframes obrot
      {
        0% { transform:rotateX(0) rotateZ(0); }
        100% { transform:rotateX(360deg) rotateZ(360deg); }
      }

      @-webkit-keyframes obrot
      {
        0% { -webkit-transform:rotateX(0) rotateZ(0); }
        100% { -webkit-transform:rotateX(360deg) rotateZ(360deg); }
      }
    </style>
  </head>

  <body>
  
    <div id="perspektywa">
      <div id="rodzic">

        <div id="przod">
          <div></div>
        </div>

        <div id="tyl">
          <div></div>
          <div></div>
        </div>

        <div id="lewo">
          <div></div>
          <div></div>
          <div></div>
        </div>

        <div id="prawo">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
        </div>

        <div id="gora">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
        </div>
		
        <div id="dol">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
        </div>

      </div>
    </div>

  </body>
</html>

W następnej części kursu CSS utworzymy karuzelę w przestrzeni perspektywy.