Анимированный кот без SVG

Предисловие

Для своего же сайта пишу шаблон, ну и в дальнейшем этот шаблон применю в wordpress. Дошло дело до страницы 404 и надо что то думать… В результате сделал анимированного «Мурзика» следящего за курсором.

Пример кота

Я как то уже делал котика следящего за курсором, но для страницы 404 хотелось чего нибудь посветлее, по этому нужно было на SVG нарисовать другого котика. На тот момент у меня не было подходящей программы под рукой, но на одном из стримов на youtube.com я случайным образом нарисовал котика на чиcтом HTML и CSS. Вот и появилась возможность сделать Мурзика с анимацией.

Запустил стрим, в котором заново нарисовал котика, и… Мне очень жаль, но скрипт не удалось сделать, пошел не тем путем, с математикой тупанул… три часа впустую...

Вечером того же дня решил переделать котика и разобраться с JS что бы на следующий день быстро все сделать...

Как рисовал кота.

В общем как нарисовать котика можно посмотреть тут, но я немного переделал уши. B место того что бы задавать цвета для border или фон для всего уха, я добавил тень. Абсолютно позиционированные уши убрал за голову с белым фоном с помощью z-index. Ну в принципе уши готовы:

less

.ear {
  border: 60px solid transparent;
  box-shadow: 0 0 0px 3px #000000;
  border-radius: 190% 0 25% 36%;
  transform: rotate(140deg);
  position: absolute;
  top: -26px;
  z-index: -1;
  &--left {
    left: 17px;
    transform: rotate(220deg) scale(-1, 1);
  }
  &--right {
    right: 17px;
  }
}

А вот и остальной код Мурзика:

less

.cat {
  margin: 0 auto;
}
.cat__head {
  position: relative;
  margin: 90px auto 0;
  width: 290px;
  height: 240px;
  border: 3px solid #000000;
  background-color: #ffffff;
  border-radius: 50%;
  box-sizing: border-box;
}
.eye {
  width: 80px;
  height: 70px;
  border-radius: 50%;
  border: 2px solid #000000;
  position: absolute;
  top: 60px;
  overflow: hidden;
  &--left {
    left: 50px;
  }
  &--right {
    right: 50px;
  }
}
.eyeball {
  width: 10px;
  height: 60px;
  border-radius: 50%;
  background-color: #000000;
  position: absolute;
  top: 5px;
  left: 35px;
}
.moustache {
  position: absolute;
  top: 70%;n  background-color: #000000;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  &--left {
    left: 70px;
  }
  &--right {
    right: 70px;
  }
  &::before,
  &::after {
    content: "";
    display: block;
    background-color: #000000;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    position: absolute;
    top: 20px;
  }
  &::before {
    left: 10px;  }
  &::after {
    right: 10px;
  }
}
.nose {
  position: absolute;
  top: 61%;
  left: 50%;
  border: 10px solid transparent;
  border-top-color: #000;
  border-left-color: #000;
  transform: translateX(-50%) rotate(45deg);
  border-radius: 32% 45% 0% 45%;
}
.mouth {
  width: 70px;
  height: 40px;
  border: 3px solid transparent;
  border-bottom: 4px solid #000000 !important;
  border-radius: 50%;
  position: absolute;
  left: 50%;
  bottom: 5%;
  transform: translateX(-50%);
}

Ну и конечно же HTML верстка:

html

<div class="cat">
    <div class="cat__head">
        <div class="ear ear--left"></div>
        <div class="ear ear--right"></div>
        <div class="eye eye--left">
            <div class="eyeball"></div>
        </div>
        <div class="eye eye--right">
            <div class="eyeball"></div>
        </div>
        <div class="nose"></div>
        <div class="moustache moustache--left"></div>
        <div class="moustache moustache--right"></div>
        <div class="mouth"></div>
    </div>
</div>

Так-то я пишу с помощью препроцессора pug, но вам даю сгенерированный HTML код.

Анимация кота:

Анимацию для нового кота просто скопировал из котика на SVG и немного поправил для нового кота:

less

@keyframes animate-ear {
  0% {
    transform: scale(1, 1) rotate(140deg);
  }
  36% {
    transform: scale(1, 1) rotate(140deg);
  }
  38% {
    transform: scale(1, 0) rotate(140deg);
  }
  42% {
    transform: scale(1, 0) rotate(140deg);
  }
  44% {
    transform: scale(1, 1) rotate(140deg);
  }
  100% {
    transform: scale(1, 1) rotate(140deg);
  }
}
@keyframes animate-eye {
  0% {
    transform: scale(1, 1);
  }
  37% {
    transform: scale(1, 1);
  }
  40% {
    transform: scale(1, 0.02);
  }
  43% {
    transform: scale(1, 1);
  }
  100% {
    transform: scale(1, 1);
  }
}

Применил эту анимацию к уху:

less

animation: animate-ear 4s;
animation-iteration-count: infinite;
transform-origin: center;

И к глазам:

less

animation: animate-eye 7s;
animation-iteration-count: infinite;
transform-origin: center;

Теперь кот моргает и шевелит ушком, осталось расшевелить глаза, а точнее зрачки.

Движение зрачков

На второй раз не стал заморачиваться со скриптом, и взял его из того же SVG котика и применил к новому коту. Во время второго стрима я код не оптимизировал. Ночью как то заглянул в этот код и решил его немного подправить в сторону производительности. В итоге вот какой код получился:

js

let eyeball = document.getElementsByClassName("eyeball"),
  y_eyeball = [],
  x_eyeball = [];
for (let n = 0; n < 2; n++) {
  let box = eyeball[n].getBoundingClientRect();
    y_eyeball.push(box.top + pageYOffset),
    x_eyeball.push(box.left + pageXOffset);
}
document.addEventListener("mousemove", function () {
  for (let n = 0; n < 2; n++) {
    setCoords(event, eyeball[n], x_eyeball[n], y_eyeball[n])
  }
})
function setCoords(event, eyeball, x_eyeball, y_eyeball) {
  x = event.pageX;
  y = event.pageY;
  x = (x - x_eyeball) / 40;
  y = (y - y_eyeball) / 40;
  let translate = "translate(" + x + "px," + y + "px)";
  eyeball.style.transform = translate;
};

В цикле в массивы добавил координаты глаз. Потом отслеживая движение курсора вызываю функцию для каждого глаза которая и двигает зрачки.

В этой функции получаю координаты курсора. В строках

js

x = (x - x_eyeball) / 40;
y = (y - y_eyeball) / 40;

Я от координат мыши отнимаю координаты курсора, для того что бы наводя курсор на зрачок глаз смотрел ровно. Потом делю на 40 (получил это число опытным путем) что бы замедлить движение зрачка. Если этого не делать, то зрачки будут всегда возле курсора)) В свойство transform — translate подставляю получившиеся числа и кот начинает следить за курсором как полагается.

Итог

В итоге получил что-что хотел. Но есть один минус, который можно поправить. Дело в том что при изменении размера окна кот будет косить)) Можно, конечно, отслеживать resize, но на данной странице я думаю этого можно и не делать.

Объявление

Если вы хотите обучаться вместе со мной, то приглашаю вас на индивидуальные курсы HTML Academy: «Профессиональная вёрстка сайтов» или «Адаптивная вёрстка и автоматизация».

Просто спросите у менеджера меня — наставника Зиновьева Александра. Обучение проходит в помесячном индивидуальном формате, и вы можете начать в любое удобное для вас время.

Кроме того, в HTML Academy вы получите профессию и даже сможете устроиться на работу с новой профессией.