Pull to refresh

Спрайтовая анимация на CSS 3

Reading time 6 min
Views 16K
Спрайтовая анимация — одна из тех вещей, которые при всей своей примитивности успешно работают и применяются в компьютерной графике и играх уже больше четверти века. Даже в трехмерных играх есть спрайты — например, билборды взрывов. Во многих браузерных и флеш-играх применяют именно спрайтовую анимацию, так как она очень проста и не требует высокой производительности — просто переключай кадры и все! А с появлением анимации в CSS 3 стало возможным использовать спрайты на своих страницах без яваскриптов.

Сразу хочу оговориться, что нижеописанный способ работает пока что только для webkit-браузеров.
Итак, возьмем простой спрайт из трех кадров:

Все, что нам надо с ним сделать, это поставить фоном в div и менять у него со временем background-position. Вроде бы все просто:
Copy Source | Copy HTML
  1. .sprite
  2. {
  3.     position: absolute;
  4.  
  5.     left: 50%; /* положение спрайта */
  6.     top: 33%;
  7.     width: 32px; /* его размер */
  8.     height: 32px;
  9.  
  10.     margin: -16px 0 0 -16px; /* просто чтобы он был по центру :-) */
  11.  
  12.     background: url(sprite.png) no-repeat 0 0; /* фон */
  13.  
  14.     -webkit-animation-name: sprite; /* название анимации */
  15.     -webkit-animation-duration: .3s; /* интервал в 300 миллисекунд */
  16.     -webkit-animation-iteration-count: infinite; /* повторять бесконечно */
  17.     -webkit-animation-timing-function: linear; /* использовать линейную функцию */
  18. }
  19.  
  20. /* анимация sprite */
  21. @-webkit-keyframes sprite
  22. {
  23.     /* перемещаем фон спрайта три раза, на четвертый возвращаем обратно в 0 */
  24.     0%
  25.     {
  26.         background-position: -0px 0;
  27.     }
  28.     33%
  29.     {
  30.         background-position: -32px 0;
  31.     }
  32.     66%
  33.     {
  34.         background-position: -64px 0;
  35.     }
  36.     100%
  37.     {
  38.         background-position: -0px 0;
  39.     }
  40. }

Но увы! В результате мы видим лишь одну порнографию. Картинка движется плавно, а не рывками длиной в кадр. Попробуем улучшить ситуацию, делая длинные интервалы и быстро переключая кадры:
Copy Source | Copy HTML
  1.  
  2. @-webkit-keyframes sprite
  3. {
  4.     0%
  5.     {
  6.         background-position: -0px 0;
  7.     }
  8.     33.332%
  9.     {
  10.         background-position: -0px 0;
  11.     }
  12.     33.334%
  13.     {
  14.         background-position: -32px 0;
  15.     }
  16.     66.665%
  17.     {
  18.         background-position: -32px 0;
  19.     }
  20.     66.667%
  21.     {
  22.         background-position: -64px 0;
  23.     }
  24.     99.999%
  25.     {
  26.         background-position: -64px 0;
  27.     }
  28.     100%
  29.     {
  30.         background-position: -0px 0;
  31.     }
  32. }
  33.  

Код получился довольно объемный, но результат нас почти устраивает, если бы не одно «но»: при маленьких интервалах можно наблюдать рывки.
Для полностью правильной анимации надо прибегнуть к другой хитрой возможности CSS 3: увеличению размера. Для этого установим ширину и высоту кадра в 1 пиксель и при помощи свойства transform увеличим спрайт до наших 32 пикселей. Так как transform влияет не только на размер самого элемента, но и на его фон, его размер установим в 3 пикселя по ширине и 1 по высоте, и в самой анимации сдвигать будем так же по 1 пикселю. Вместе с увеличением оно как раз и будет равно 32 пикселям.
Copy Source | Copy HTML
  1.  
  2. .sprite
  3. {
  4.     position: absolute;
  5.  
  6.     left: 50%;
  7.     top: 33%;
  8.     width: 1px; /* размеры элемента ставим в 1 пиксель */
  9.     height: 1px;
  10.  
  11.     margin: -16px 0 0 -16px; /* на отступы увеличение через transform не влияет */
  12.  
  13.     background: url(sprite.png) no-repeat 0 0;
  14.     background-size: 3px 1px; /* размер фона также уменьшаем */
  15.  
  16.     -webkit-animation-name: sprite;
  17.     -webkit-animation-duration: .3s;
  18.     -webkit-animation-iteration-count: infinite;
  19.     -webkit-animation-timing-function: linear;
  20.     -webkit-transform: scaleX(32) scaleY(32); /*  увеличим размер элемента */
  21.     -webkit-transform-origin: top left;
  22. }
  23.  
  24. @-webkit-keyframes sprite
  25. {
  26.     /* сдвигаем фон по 1 пикселю */
  27.     0.000%
  28.     {
  29.         background-position: -0px 0;
  30.     }
  31.     25.000%
  32.     {
  33.         background-position: -1px 0;
  34.     }
  35.     50.000%
  36.     {
  37.         background-position: -2px 0;
  38.     }
  39.     /* честно говоря, сам не понял, зачем надо сдвигать */
  40.     /* еще на один пиксель (ведь это должен быть */
  41.     /* пустой кадр). но иначе оно не покажет все */
  42.     /* кадры анимации. */
  43.     75.000%
  44.     {
  45.         background-position: -3px 0;
  46.     }
  47.     100.000%
  48.     {
  49.         background-position: -0px 0;
  50.     }
  51. }
  52.  

Теперь результат полностью соответствует нашим ожиданиям. Анимация нормальная, без рывков и прочего.
Для генерации ключевых кадров можно воспользоваться этой функцией:
Copy Source | Copy HTML
  1. function generateKeyframes($count, $sprite_width)
  2. {
  3.     $result = '';
  4.     $count++;
  5.     for ($i =  0; $i <= $count; $i++)
  6.     {
  7.         $result .= sprintf("\t%.3f%%\n\t{\n\t\tbackground-position: -%dpx 0;\n\t}\n", $i * 100. 0 / $count, ($i % $count) * $sprite_width);
  8.     }
  9.     return $result;
  10. }

Увы, этот способ пока что малоприменим на практике, так как работает только в Webkit-браузерах типа Chrome или Safari. В Firefox анимация так и останется плавной, в Opera показывается только первый кадр, а в IE оно вообще не работает. Так что анимация с использованием Javascript и Flash будет держать свои позиции еще довольно долго.
Tags:
Hubs:
+49
Comments 24
Comments Comments 24

Articles