CSS3 - Animowany obrazek klatka po klatce

W tej części kursu CSS utworzymy animowany obrazek, wykorzystując do tego celu wyłącznie język CSS.

Efekt końcowy został przedstawiony poniżej:

Wbrew pozorom utworzenie animowanego obrazka nie jest niczym trudnym, lecz wymaga to od nas podania dość precyzyjnych wartości we właściwościach CSS, które znajdą się w naszym kodzie, natomiast sam obrazek będzie musiał być odpowiednio przygotowany, przez nas, w programie graficznym, np. w GIMP-ie.

Zaczniemy od przygotowania odpowiedniego obrazka. Wpisując w wyszukiwarkę internetową, np. Google, słowa free sprites, dzięki czemu wyświetlą się nam przykładowe obrazki, które możemy wykorzystać w naszym przykładzie. Obrazek taki musimy odpowiednio przygotować. Pod spodem został przedstawiony gotowy obrazek, który wykorzystamy w naszym przykładzie. duszki lwa Nasz obrazek prezentuje czternaście lwów, które są umieszczone jeden pod drugim. Ważne, aby każdy taki wizerunek lwa miał takie same rozmiary, dla ułatwienia wymiary te zostały zaznaczone na obrazku, który został umieszczony poniżej, za pomocą kolorowych teł. duszki lwa Jak na razie będziemy korzystać z obrazka, który został umieszczony powyżej, dzięki czemu łatwiej zrozumiemy cały proces, który wprawi nasz obrazek w ruch.

Do części body dokumentu HTML dodajemy element div bez zawartości. Do elementu div dodajemy atrybut class o wartości lwy oraz atrybut id o wartości lew_pierwszy.

<body>

  <div id="lew_pierwszy" class="lwy"></div>

</body>

Musimy nadać odpowiednią wartość szerokości oraz wysokości dla naszego elementu div. Wartości te będą uzależnione od naszego obrazka, a dokładniej od szerokości oraz wysokości pojedynczego lwa. Wartością szerokości naszego obrazka jest wartość 90px, natomiast wartością wysokości pojedynczego obszaru z lwem jest wartość 50px. Po ustaleniu wspomnianych wymiarów dla elementu div, wypełniamy jego tło obrazkiem oraz sprawiamy, aby tło nie powtarzało się, obie czynności wykonujemy za pomocą właściwości background.

.lwy {
  width:90px;
  height:50px;
  background:url('http://webkod.pl/images/lions_backs.png') no-repeat;
}

Rezultat:

Naszym następnym krokiem będzie wprawienie w ruch tła obrazkowego elementu div. Powinniśmy już wiedzieć jak to uczynić, ponieważ było to opisane w jednej z poprzednich części tego działu - CSS3 - Tworzymy ruchome tło w elemencie HTML. Różnica polega na tym, że w tej części kursu CSS będziemy poruszać tylko jednym tłem obrazkowym elementu HTML.

Musimy wiedzieć o jaką wartość będziemy chcieli przesunąć nasz obrazek w górę. Wartość ta będzie całkowitą wartością wysokości naszego obrazka, który składa się z czternastu lwów, z których każdy ma 50px wysokości. Po wykonaniu prostego działania 50px × 14 = 700px otrzymujemy szukaną wartość. Naszą wartość podajemy jako wartość ujemną dla właściwości background-position, dlatego tło obrazkowe elementu HTML będzie przesuwać się w górę, gdy utworzymy animację oraz dodamy ją do danego elementu HTML.

Tworzymy animację:

@keyframes bieg_lwa
{
  0% { background-position:0 0; }
  100% { background-position:0 -700px; }
}

W ten sposób utworzoną animację bieg_lwa dodajemy do naszego elementu div.

#lew_pierwszy {
  animation:bieg_lwa 5s linear infinite;
}

Rezultat:

Nie do końca o taki efekt nam chodziło, dlatego czas skorzystać z funkcji steps(), która określa tempo animacji (aktualnie tym tempem jest wartość linear).

O funkcji steps() mogliśmy przeczytać w poprzedniej części tego kursu CSS. Jako parametr funkcji steps() należy podać liczbę klatek z jakiej ma składać się nasza animacja, a więc podamy liczbę 14, ponieważ z tylu obszarów z lwem, o stałej wartości szerokości oraz wysokości, składa się nasz obrazek. Domyślnie ostatnia klatka będzie pomijana przez funkcję steps() i dobrze, ponieważ nie zobaczymy, przez chwilę, naszego elementu div bez tła obrazkowego, tak jak ma to miejsce w przykładzie, który został umieszczony powyżej.

Zamieniamy wartość linear na funkcję steps(14).

#lew_pierwszy {
  animation:bieg_lwa 5s steps(14) infinite;
}

Rezultat:

Od tej pory tempo animacji bieg_lwa jest określane przez funkcję steps(14), dzięki czemu nasza animacja składa się z czternastu klatek, które są pokazywane w równych odstępach czasu (ostatnia klatka animacji jest pomijana). Możemy przyspieszyć cały efekt, określając krótszy czas całej animacji.

Zamieniamy wartość 5s na 500ms.

#lew_pierwszy {
  animation:bieg_lwa 500ms steps(14) infinite;
}

Rezultat:

Czas stworzyć odbicie naszego animowanego obrazka. Moglibyśmy skorzystać z właściwości box-reflect, lecz jest ona słabo wspierana przez poszczególne przeglądarki internetowe, dlatego poradzimy sobie inaczej z tą sytuacją, przy okazji poćwiczymy znajomość właściwości transform oraz jej funkcji.

Dodajemy drugi element div do części body, dla którego określamy tą samą wartość atrybutu class oraz inną wartość atrybutu id.

<body>

  <div id="lew_pierwszy" class="lwy"></div>
  <div id="lew_drugi" class="lwy"></div>

</body>

Dodajemy animację bieg_lwa do nowego elementu div.

#lew_drugi {
  animation:bieg_lwa 500ms steps(14) infinite;
}

Rezultat:

Do elementu z drugim lwem dodajemy właściwość transform wraz z funkcją rotateX(180deg), dzięki czemu element HTML zostanie obrócony o 180 stopni względem osi X, czyli po prostu zostanie odwrócony do góry nogami.

#lew_drugi {
  animation:bieg_lwa 500ms steps(14) infinite;
  transform:rotateX(180deg);
}

Rezultat:

Nasze lwy biegają w miejscu. Czas, aby to zmienić.

Tworzymy nową animację, która sprawi, że element HTML będzie poruszał się w prawą stronę o 300 pikseli. Wspomniany efekt uzyskamy dzięki właściwości transform oraz funkcji translateX(300px). Dla obu lwów będziemy potrzebowali osobnych animacji, ponieważ drugi z nich musi pozostać odwrócony do góry nogami, a więc musi posiadać, przez cały czas trwania animacji, funkcję rotateX(180deg) we właściwości transform, w regule @keyframes.

@keyframes droga_lew-1
{
  0% { transform:translateX(0) scale(1); }
  100% { transform:translateX(300px) scale(0.1); }
}

@keyframes droga_lew-2
{
  0% { transform:rotateX(180deg) translateX(0) scale(1); }
  100% { transform:rotateX(180deg) translateX(300px) scale(0.1); }
}

W ten sposób utworzone animacje dodajemy do naszych elementów div.

#lew_pierwszy {
  animation:bieg_lwa 500ms steps(14) infinite, droga_lew-1 10s infinite alternate;
}

#lew_drugi {
  animation:bieg_lwa 500ms steps(14) infinite, droga_lew-2 10s infinite alternate;
  transform:rotateX(180deg);
}

Rezultat:

Do właściwości transform, która znajduje się w naszych regułach @keyframes, dodatkowo została dodana funkcja scale(), która odpowiada za pomniejszenie oraz powiększenie elementu HTML. Natomiast dzięki wartości alternate, która została użyta we właściwości animation, nasza animacja powtarza się od końca do początku i na odwrót.

Pozostał nam do rozwiązania jeden problem, ponieważ oba lwy nie przylegają do siebie, bo elementy div są pomniejszane przez funkcję scale(0.1). Wyjaśnienie rozwiązania tego problemu może wydać się dość skomplikowane na samym początku.

Do właściwości transform, która znajduje się w animacji droga_lew-2, należy dodać funkcję translateY(), która zmienia pozycję elementu HTML względem pionu.

Ponieważ w końcowej fazie obu animacji droga_lew-1 oraz droga_lew-2, które mają takie samo tempo oraz ten sam czas wykonywania się, wysokość obu elementów div wynosi scale(0.1), czyli 10% początkowej wysokości, to wartość jaką należy użyć w funkcji translateY(), dla selektora czasu animacji droga_lew-2 100%, będzie równa początkowa wysokość elementu HTML - początkowa wysokość elementu HTML × 0.1, czyli 50px - 50px × 0.1 = 45px.

@keyframes droga_lew-2
{
  0% {transform:rotateX(180deg) translateX(0) translateY(0) scale(1);}
  100% {transform:rotateX(180deg) translateX(300px) translateY(45px) scale(0.1);}
}

Rezultat:

W normalnych okolicznościach funkcja translateY(45px) przesunęłyby element HTML w dół ekranu, natomiast jeżeli chcielibyśmy, aby element HTML został przesunięty w górę ekranu, to musielibyśmy podać wartość ujemną, czyli np. -45px, jednak w naszym przypadku nie musimy tego robić, ponieważ obrazek został wcześniej odwrócony do góry nogami, za pomocą funkcji rotateX(180deg).

Do reguły CSS, która odpowiada za wygląd drugiego lwa, dodajemy właściwość opacity:0.1; dzięki czemu element stanie się bardziej przezroczysty, a jego kolor wyblaknie. Możemy zmienić nasz obrazek z lwami na ten bez kolorowych teł, dzięki czemu uzyskamy nasz finalny efekt.

.lwy {
  width:90px;
  height:50px;
  background:url('http://webkod.pl/images/lions.png') no-repeat;
}

#lew_drugi {
  animation:bieg_lwa 500ms steps(14) infinite, droga_lew-2 10s infinite alternate;
  transform:rotateX(180deg);
  opacity:0.1;
}

Finalny rezultat:

Kod dokumentu HTML:

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

    <style>
      .lwy {
        width:90px;
        height:50px;
        background:url('http://webkod.pl/images/lions.png') no-repeat;
      }

      #lew_pierwszy {
        animation:bieg_lwa 500ms steps(14) infinite, droga_lew-1 10s infinite alternate;
        -webkit-animation:bieg_lwa 500ms steps(14) infinite, droga_lew-1 10s infinite alternate;
      }

      #lew_drugi {
        animation:bieg_lwa 500ms steps(14) infinite, droga_lew-2 10s infinite alternate;
        -webkit-animation:bieg_lwa 500ms steps(14) infinite, droga_lew-2 10s infinite alternate;
        transform:rotateX(180deg);
        -webkit-transform:rotateX(180deg);
        opacity:0.1;
      }

      /*-------------------ANIMACJE-------------------*/
      @keyframes bieg_lwa
      {
        0% {background-position:0 0;}
        100% {background-position:0 -700px;}
      }

      @keyframes droga_lew-1
      {
        0% {transform:translateX(0) scale(1);}
        100% {transform:translateX(300px) scale(0.1);}
      }

      @keyframes droga_lew-2
      {
        0% {transform:rotateX(180deg) translateX(0) translateY(0) scale(1);}
        100% {transform:rotateX(180deg) translateX(300px) translateY(45px) scale(0.1);}
      }

      /* dla przeglądarki Google Chrome, Safari, Opera 15+ */
      @-webkit-keyframes bieg_lwa
      {
        0% {background-position:0 0;}
        100% {background-position:0 -700px;}
      }

      @-webkit-keyframes droga_lew-1
      {
        0% {-webkit-transform:translateX(0) scale(1);}
        100% {-webkit-transform:translateX(300px) scale(0.1);}
      }

      @-webkit-keyframes droga_lew-2
      {
        0% {-webkit-transform:rotateX(180deg) translateX(0) translateY(0) scale(1);}
        100% {-webkit-transform:rotateX(180deg) translateX(300px) translateY(45px) scale(0.1);}
      }
    </style>
  </head>

  <body>

    <div id="lew_pierwszy" class="lwy"></div>
    <div id="lew_drugi" class="lwy"></div>

  </body>
</html>

W następnej części kursu CSS utworzymy coś co jest zwane Tooltip CSS.