Анимированные животные на CSS и SVG

Сегодня я покажу вам, как использовать чистый HTML, упорядоченную CSS анимацию, а также SVG фильтры для реализации невероятной (и восхитительной) идеи - анимированные животные на веб-странице. Мы воспользуемся двумя методами для рисования животных: первый метод - простой HTML и CSS, второй метод - инлайновые фоновые SVG изображения.

Сложность

В демонстрационном примере мы работаем с анимированными SVG фильтрами, которые в настоящее время доступны только для Chrome.

Упорядоченная анимация - довольно сложная в реализации, поэтому в этом руководстве мы сосредоточимся на различных методах, которые помогут создать животных в движении. После того как вы прочтете данное руководство, вы сможете самостоятельно создавать уникальных, анимированных животных.

Формирование животных

Для демонстрационного примера, мы воспользуемся двумя методами формирования разных частей животных. Различные CSS свойства, такие как border-radius, а также инлайновые фоновые SVG изображения, помогут создать сложные, комплексные формы.

HTML разметка

Оба животных используют множество вложенных HTML-контейнеров в качестве частей тела. Концепция группировки имеет большое значение, для того, чтобы животные выглядели более живыми. Движение частей тела также имеет важную роль, например, когда движется голова, глаза и уши тоже должны двигаться.

<!-- Разметка головы лисы -->
<div class="fox-head">
  <div class="fox-face">            
    <div class="fox-ears">
      <div class="fox-ear"></div>
      <div class="fox-ear"></div>
    </div>
    <div class="fox-skull"></div>
    <div class="fox-front"></div>
    <div class="fox-eyes"></div>
    <div class="fox-nose"></div>
  </div>
</div>

<!-- Разметка головы хаски -->
<div class="husky-head">
  <div class="husky-ear"></div>
  <div class="husky-ear"></div>
  <div class="husky-face">
    <div class="husky-eye"></div>
    <div class="husky-eye"></div>
    <div class="husky-nose"></div>
    <div class="husky-mouth">
      <div class="husky-lips"></div>
      <div class="husky-tongue"></div>
    </div>
  </div>
</div>

Каждая часть может двигаться независимо друг от друга, а также будет двигаться вместе со своим родительским элементом, что создает более реалистичный эффект. Обратите внимание, что сам хвост глубоко вложен в других компонентах хвоста. Каждая хвостовая часть позиционируется относительно его родителя, а затем происходит вращение всех частей, что создает иллюзию равномерной кривой.

css хвост животного

CSS

Свойство border-radius активно используется для формирования хаски при помощи CSS. Для многих элементов, требуется индивидуальный контроль каждого свойства border-radius. Пример формирования лапы хаски:

.husky-hind-leg {
  // ...
  border-top-left-radius: 35% 100%;
  border-top-right-radius: 40% 100%;
}

Первое число указывает на то, насколько глубоко кривая проходит по верхнему/нижнему краю, а второе число - насколько глубоко кривая проходит по левому/правому краю.

Другие части животного, такие как передние лапы, не могут быть сформированы используя только border-radius, необходимо будет добавить также свойство transform:

.husky-front-legs > .husky-leg:before {
  transform: skewY(-30deg) skewX(10deg);
  transform-origin: top right;
}

После того, как все формы на своем месте, каждый элемент располагается абсолютно, в процентном соотношении, на основе позиции своего родителя. Это обеспечивает точное размещение каждой части тела, а также скорость отклика.

Формирование в SVG

Для лисы, используем Sass-SVG для создания сложной SVG формы каждой части тела. SVG-изображения могут быть использованы в качестве фона, и даже лучше, они могут быть расположены в ряд.

Нарисовать их вручную довольно сложно. Я использовал Adobe Illustrator для создания начальных форм:

svg лиса

Затем я сохранил каждую часть тела в качестве SVG изображения. SVG код был переведен в SCSS через Sass-SVG. К примеру, так выглядит нос лисы:

.fox-nose:before {
  @include svg((viewBox: (0 0 168 168))) {
    // нос
    @include svg('path', (
      fill: $color-nose,
      d: 'M83.7,86.7c3.3,0,11.6-3.9,11.6-7.1c0-3.2-9.4-3.2-11.6-3.2c-2.2,0-11.6,0-11.6,3.2   C72.1,82.8,80.4,86.7,83.7,86.7z'
    ));

    // линия соединяющая нос и рот
    @include svg('path', (
      stroke: $color-nose,
      fill: none,
      d: 'M83.7,102.3V86.7'
    ));

    // рот
    @include svg('path', (
      stroke: $color-nose,
      fill: none,
      d: 'M94.5,104.9c0,0-5.2-2.7-10.8-2.7c-5.6,0-10.8,2.7-10.8,2.7'
    ));
  }
}

В итоге у нас получится SVG строка внутри URL, которая выглядит следующим образом:

.fox-nose:before {
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg...");
}

Поскольку SVG это - фоновое изображение, оно может быть преобразовано и анимировано, как если бы это был простой HTML элемент. При помощи Sass-SVG, мы можем использовать Sass $переменные, для того, чтобы иметь полный контроль над цветом SVG fill и stroke.

Так как мы работаем с инлайн SVG, довольно просто адаптировать лису. Значения атрибутов ((viewBox: (0 0 168 168))) берутся напрямую из SVG файла, но до тех пор, сохраняется соотношение высоты/ширины элемента, который содержит фоновое SVG изображение и может быть любого размера. Все части головы лисы позиционируются абсолютно, той же высоты и ширины, что и .fox-head.

SVG фильтры

Мы используем технику Squigglevision, для анимации различных частей фигуры. Это улучшит динамику сцены с лисой и хаски, даже когда животные не двигаются.

SVG имеет фильтр под названием <feTurbulence>, который добавляет "шум" к применяемому элементу. Фильтр <feTurbulenceMap>, служит для объединения фильтров и определяет, как далеко пиксели должны двигаться друг от друга, в каждом из них.

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="squiggly-0">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="0"/>
      <feDisplacementMap id="displacement" in="SourceGraphic" in2="noise" scale="2" />
    </filter>
    <filter id="squiggly-1">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="1"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="3" />
    </filter>
    
    <filter id="squiggly-2">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="2"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="2" />
    </filter>
    <filter id="squiggly-3">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="3"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="3" />
    </filter>
    
    <filter id="squiggly-4">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="4"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="1" />
    </filter>
  </defs> 
</svg>

Каждый фильтр имеет несколько различных атрибутов. Данные фильтры можно применить к любому элементу с помощью CSS свойства filter: url(...);. Для того, чтобы создать эффект "squigglevision", воспользуемся ключевыми кадрами, которые будут запускать различные фильтры.

@keyframes squigglevision {
  0% {
    -webkit-filter: url('#squiggly-0');
    filter: url('#squiggly-0');
  }
  25% {
    -webkit-filter: url('#squiggly-1');
    filter: url('#squiggly-1');
  }
  50% {
    -webkit-filter: url('#squiggly-2');
    filter: url('#squiggly-2');
  }
  75% {
    -webkit-filter: url('#squiggly-3');
    filter: url('#squiggly-3');
  }
  100% {
    -webkit-filter: url('#squiggly-4');
    filter: url('#squiggly-4');
  }
}

Данные SVG фильтры не работают в Firefox, скорее всего, их поддержка будет добавлена в следующих обновлениях.

Анимация животных

CSS ключевые кадры не самый удобный способ конвертирования в squigglevision. Лучший способ подойти к этой проблеме заключается в планировании (раскадровки) анимации как временной шкалы и использовать препроцессор, например Sass для создания ключевых кадров.

Для лисы, используем transforms и смещение времени (в секундах) для анимации каждой части тела, чтобы получить кадры анимации по отдельности. Вот пример того, как мы разложили нос лисы в SCSS:

$animations: (
  // ...

  'nose': (
    // положение покоя
    (4s, 5s, 7s): rotateY(-4deg),

    // нос вниз
    4.5s: rotateY(-4deg) rotateX(-3deg),

    // лиса смотрит влево
    (7.5s, 9s): rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg),

    // лиса смотрит вправо
    (9.5s, 12s): rotateY(7deg),

    // лиса смотрит вперед
    13s: rotateY(0),
  ),

  // ...
);

Здесь, переменная $animations является Sass картой, где ключ - это имя анимации (например, "nose"). Значение каждого имени анимации - еще одна карта, где ключом является смещение или список смещений в секундах (например, (7.5s, 9s)), а значение это - преобразованное свойство для каждого смещения ключа.

Итак, как мы можем превратить эту карту в @keyframe анимацию? Во-первых, установим глобальную переменную $duration: 17s - это будет общая продолжительность каждой анимации. Затем, используя вложенный Sass цикл @each ... in ..., мы можем cгенерировать CSS @keyframe для каждой анимации, благодаря перебору карты $animations:

@each $animation-name, $animation in $animations {
  @keyframes #{$animation-name} {
    @each $offsets, $transform in $animation {
      @each $offset in $offsets {
        #{percentage($offset / $duration)} {
          transform: #{$transform};
        }
      }
    }
  }
}

Сгенерированные ключевые кадры выглядят следующим образом:

@keyframes nose {
  14.70588% {
    transform: rotateY(-4deg); }
  23.52941% {
    transform: rotateY(-4deg); }
  29.41176% {
    transform: rotateY(-4deg); }
  41.17647% {
    transform: rotateY(-4deg); }
  26.47059% {
    transform: rotateY(-4deg) rotateX(-3deg); }
  44.11765% {
    transform: rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg); }
  52.94118% {
    transform: rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg); }
  55.88235% {
    transform: rotateY(7deg); }
  70.58824% {
    transform: rotateY(7deg); }
  76.47059% {
transform: rotateY(0); } }

Без SCSS, было бы очень утомительно рассчитывать данные проценты вручную. Они представляют собой процентное смещение каждого требуемого значения времени в каждом шаге нашей анимации, по отношению к общей $duration.

Анимации можно применить к соответствующим частям тела, например: animation: nose $duration none infinite;. Очень важно, чтобы каждая анимация имела одинаковую длительность, для того, чтобы их можно было легко зациклить.

ДЕМО СКАЧАТЬ

 

Перевод статьи Animated Animals in CSS and SVG

Тэги: transitionanimatescss

Вход

Уважаемый пользователь! Мы обнаружили, что вы используете AdBlock и вынуждены скрыть часть материалов на нашем сайте. Siteacademy существует и развивается за счет доходов от рекламы. Просим внести наш сайт в список исключений или отключить Блокировщик рекламы на нашем сайте.