Казалось бы, нет ничего проще, чем найти на просторах Сети нехитрый код анимации CSS и анимировать какой-либо объект, благо библиотек анимации предостаточно. Не нужно обладать какими-то сверх-познаниями, чтобы это сделать, код достаточно прост и понятен, даже новичку. Сегодня практически все браузеры, от мала до велика, её поддерживают, и это здорово. Однако чем больше занимаешься веб-дизайном, тем чаще появляется необходимость в индивидуальных решениях и усложнении кода. Вот тут и начинаются проблемы…
Дело в том, что анимация, в которой много разнообразных трансформаций ведёт себя абсолютно непредсказуемо, она подвисает или попросту воспроизводится не так, как мы того ожидали.
Для примера попробую простенький код HTML, заодно вспомню «Алису в стране чудес»:
<div class="smile-box">
<div class="smile"></div>
</div>
Добавлю стили:
body {
margin: 0;
padding: 0;
background: rgb(253, 250, 233);
display: flex;
justify-content: center;
}
.smile-box {
max-width: 1000px;
width: 100%;
height: 100px;
margin-top: 5em;
background: linear-gradient(rgb(179, 208, 236), rgb(152, 85, 240));
display: flex;
align-items: center;
overflow: hidden;
}
.smile {
width: 80px;
height: 80px;
border-radius: 50%;
background: rgb(250, 173, 101) url(smile.png) no-repeat center center;
background-size: 75%;
transform: translateX(-100px);
box-shadow: inset 0 0 50px rgba(151, 87, 28, 0.7), 0 0 5px rgb(151, 87, 28);
}
Представьте: мне необходимо, чтобы при наведении курсора на родительский контейнер улыбка Чеширского кота «катилась» вправо. Для этого мне понадобится две трансформации: вокруг своей оси и слева-направо.
.smile-box:hover>.smile {
animation: 3.2s linear infinite reverse spin-to-right;
}
@keyframes spin-to-right {
0% {
transform: translateX(1000px) rotate(360deg);
}
100% {
transform: translateX(-100px) rotate(0deg);
}
}
Анимация прекрасно работает, достаточно навести курсор на дорожку:
See the Pen Complex CSS animation is a lot of simple solutions-1 by haracan (@haracan) on CodePen.
Теперь попробую сделать так, чтобы «улыбка» не просто двигалась вправо по прямой, а двигалась волнообразно или подпрыгивала на лету, как мячик. Попробую в свою анимацию добавить трансформацию по оси Y (translateY
) — но код не работает как надо; код не будет работать, даже если разбить одну сложную анимацию на две. Это происходит потому, что все мои трансформации применены к одному объекту. Иногда удаётся что-то настроить, и вроде бы анимация воспроизводится нормально, но стоит открыть страничку в другом браузере, и объект начинает вести себя странно.
Было время, когда в подобных случаях я начинал рвать на себе волосы, и бесконечно правил CSS, и фантазировал, но в конце концов до меня дошло, что дело вовсе не в CSS и не в анимации, проблема в HTML. То есть всё дело в боксе, к которому применяется трансформация. Для корректного воспроизведения анимации необходимо добавить ему «обёртку»:
<div class="smile-box">
<div class="smile-wrapper">
<div class="smile"></div>
</div>
</div>
Далее следует скорректировать код CSS таким образом, чтобы на «обёртку» и «улыбку» приходилось по одной простой анимации:
.smile-wrapper {
width: 80px;
height: 80px;
transform: translateX(-100px);
}
.smile {
width: 100%;
height: 100%;
border-radius: 50%;
background: rgb(250, 173, 101) url(smile.png) no-repeat center center;
background-size: 75%;
box-shadow: inset 0 0 50px rgba(151, 87, 28, 0.7), 0 0 5px rgb(151, 87, 28);
}
.smile-box:hover>.smile-wrapper>.smile {
animation: 3.2s linear infinite reverse spin-to-right;
}
.smile-box:hover>.smile-wrapper {
animation: 3.2s ease infinite reverse wave;
}
Сделаю оптимальное количество «волн» во второй анимации, ведь расстояние относительно «улыбки» совсем небольшое, но можно сделать и больше.
@keyframes spin-to-right {
0% {
transform: translateX(1000px) rotate(720deg);
}
100% {
transform: translateX(-100px) rotate(0deg);
}
}
@keyframes wave {
0%,
28.4%,
56.8%,
85.6% {
transform: translateY(5px);
}
14.2%,
42.6%,
71%,
100% {
transform: translateY(-5px);
}
}
В результате получилось то, чего я и добивался:
See the Pen Complex CSS animation is a lot of simple solutions-2 by haracan (@haracan) on CodePen.
Подобным образом можно оформить самую разнообразную анимацию, особенно такую, где необходимо, чтобы разная трансформация по X и Y применялась одновременно к одному и тому же объекту. То же относится и к развороту по оси. Например, иногда необходимо, чтобы во время воспроизведения анимации вдруг появлялась какая-то трансформация, которая уже используется нами и имеет свои значения, — в этом случае мы можем задать одну и ту же трансформацию основному объекту и его оболочке, назначив каждому из объектов отдельную анимацию и выставив разные значения одинаковой трансформации.
Проиллюстрирую это парашютистом, совершающем пируэты в небесах. Дам ему плавно разворачиваться по оси во время всего полёта вниз и одновременно заставлю его где-нибудь в середине пути совершить пируэт, развернувшись на 360 градусов. Заодно при помощи трансформации scale()
создам эффект отдаления и приближения. Обратите внимание на то, что изначально у меня выставлено transform: scale(0.7)
, а не единица. Это сделано для того, чтобы объект при увеличении не терял чёткие контуры, а как бы возвращался в процессе трансформации к своему истинному размеру. Сначала в HTML создам простой код, наш парашютист будет состоять из трёх объектов, вложенных один в другой:
<div class="sky">
<div class="pilot-wrapper">
<div class="pilot">
<img src="pilot.png">
</div>
</div>
</div>
В CSS задам стили каждому объекту, при этом к некоторым сразу же применю трансформацию, которая в дальнейшем будет использоваться в анимации, это необходимо, чтобы трансформация начиналась плавно и не деформировала объекты (как в случае со scale()
):
body {
margin: 0;
padding: 0;
text-align: center;
}
.sky {
max-width: 500px;
width: 100%;
height: 100vh;
background: linear-gradient(rgb(88, 85, 240), rgb(179, 208, 236));
display: inline-block;
overflow: hidden;
}
.pilot-wrapper {
width: 200px;
height: 100px;
position: relative;
left: 30%;
transform: translateY(-110px);
}
.pilot {
transform: scale(0.7);
}
.pilot img {
width: 100%;
height: 100%;
}
Теперь собственно сама анимация, которая будет начинаться при наведении на импровизированное небо и повторятся один раз:
.sky:hover>.pilot-wrapper>.pilot>img {
animation: 2.5s ease-in 7s rotate;
}
.sky:hover>.pilot-wrapper>.pilot {
animation: 17s ease-in-out 1 reverse wave-scale;
}
.sky:hover>.pilot-wrapper {
animation: 15s ease-in-out 1 reverse to-bottom-rotate;
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes to-bottom-rotate {
0% {
transform: translateY(100vh) rotate(-45deg);
}
100% {
transform: translateY(-110px) rotate(45deg);
}
}
@keyframes wave-scale {
0% {
transform: translateX(100px);
}
20% {
transform: translateX(-150px) scale(1);
}
40% {
transform: translateX(100px);
}
60% {
transform: translateX(-150px) scale(0.7);
}
80% {
transform: translateX(100px);
}
100% {
transform: translateX(-150px) scale(1);
}
}
Итог трудов получился забавным:
See the Pen Complex CSS animation is a lot of simple solutions-3 by haracan (@haracan) on CodePen.
Скорее всего это не идеальный код (как всё в этом мире), однако я и не ставил своей задачей добиться совершенства, мне было необходимо решить проблему сложной анимации. Попробуйте улучшить его, у вас должно получиться.