Содержание

Добавляем статичным объектам выразительность с помощью базовых анимаций
3 минуты чтения
Содержание
Веб-плакат живёт во времени. В отличие от печатного плаката, где динамика передаётся через композицию и экспрессию формы, здесь движение — буквальное. Элементы вращаются, смещаются, пульсируют, дрейфуют по экрану. CSS-анимации через @keyframes дают дизайнеру контроль над тем, как и когда зритель воспринимает визуальное сообщение. Замедлить, ускорить, зациклить — всё это становится частью авторского инструментария.
Объект едет из точки A в точку B по прямой. Туда — обратно, туда — обратно. Или просто туда и исчезает. Это самый базовый тип движения, и начинать стоит именно с него — чтобы почувствовать, как вообще работает связка @keyframes + animation
Технически всё просто: вы описываете два состояния — начальное и конечное, — а браузер интерполирует переход между ними. Свойство animation-direction: alternate заставляет объект возвращаться обратно, создавая маятниковый эффект. А infinite зацикливает движение, чтобы анимация не останавливалась.
Обратите внимание на calc(100% - 80px) — это способ сделать так, чтобы объект не вылезал за границы контейнера. Функция calc() вычитает ширину самого элемента из ширины родителя, и квадрат аккуратно доезжает до правого края. Без этого приёма объект частично уедет за пределы видимой области.
<div class="demo-cube"></div>
.demo-cube {
position: absolute;
animation: movement-linear 5s linear infinite alternate;
}
@keyframes movement-linear {
from {
left: 0;
}
to {
left: calc(100% - 40px);
}
}
/* Вычитаем ширину 40 px объекта для корректной анимации */
Представьте маятник настенных часов или качели. Объект раскачивается вокруг точки опоры — медленно в крайних положениях, быстрее в центре. Этот характер движения ощущается естественным, потому что мы видим его в физическом мире постоянно.
Секрет колебательного движения — в свойстве transform-origin. По умолчанию вращение через rotate происходит вокруг центра элемента, что выглядит как кручение на месте. Стоит сместить точку трансформации — скажем, в верхнюю часть объекта — и вращение превращается в качание, словно объект подвешен на нитке.
<div class="demo-pendulum">
<div class="demo-pendulum-ball"></div>
</div>
@keyframes movement-pendulum {
from {
transform: rotate(-25deg);
}
to {
transform: rotate(25deg);
}
}
.demo-pendulum {
position: absolute;
top: 10%;
left: 50%;
width: 6px;
height: 180px;
background: rgba(255, 255, 255, 0.3);
/* Точка опоры — верхний центр */
transform-origin: top center;
animation: movement-pendulum 2s ease-in-out infinite alternate;
}
.demo-pendulum-ball {
position: absolute;
bottom: -20px;
left: 50%;
width: 40px;
height: 40px;
border-radius: 50%;
background: #fff;
transform: translateX(-50%);
}
Частая ошибка — забыть про transform-origin. Без его настройки rotate вращает объект вокруг собственного центра, и вместо маятника вы получаете вертушку. Если вам нужно качание — всегда задавайте точку опоры явно.
Объект ритмично увеличивается и уменьшается — как будто дышит. Пульсация отлично работает для привлечения внимания к конкретному элементу: кнопке, логотипу, точке на карте. При этом она достаточно мягкая, чтобы не раздражать, особенно если использовать плавный тайминг и умеренную амплитуду.
Реализуется через transform: scale() Важно понимать разницу между пульсацией и «морганием»: пульсация — это масштабирование, а моргание — это смена прозрачности через opacity Кайфовое решение: комбинировать оба свойства. Когда объект одновременно увеличивается и становится чуть прозрачнее на пике, эффект выглядит живее.
<div class="demo-pulse-circle"></div>
@keyframes movement-pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.3);
opacity: 0.7;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.demo-pulse-circle {
position: absolute;
top: 50%;
left: 50%;
width: 80px;
height: 80px;
border-radius: 50%;
background: #fff;
transform: translate(-50%, -50%);
animation: movement-pulse 2s ease-in-out infinite;
}
Мягкое, почти незаметное перемещение — как если бы объект плыл в невесомости. Дрифт работает в медитативных, атмосферных композициях и часто используется для фоновых слоёв: декоративных фигур, текстур, размытых пятен.
Весь фокус в длительности и комбинировании. Одна анимация сдвигает объект по оси X, другая — по оси Y, третья — немного вращает. У каждой своя длительность, и так как эти длительности не кратны друг другу, суммарная траектория получается сложной и непредсказуемой. Зритель не может «считать» паттерн повторения — движение кажется хаотичным, хотя каждая ось строго предсказуема.
<div class="demo-drift-wrapper-x">
<div class="demo-drift-wrapper-y">
<div class="demo-drift-element"></div>
</div>
</div>
@keyframes drift-x {
0%, 100% { transform: translateX(0); }
50% { transform: translateX(80px); }
}
@keyframes drift-y {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-60px); }
}
@keyframes drift-rotate {
0%, 100% { transform: rotate(0deg); }
50% { transform: rotate(15deg); }
}
/* Обёртки для наложения нескольких transform-анимаций */
.demo-drift-wrapper-x {
position: absolute;
top: 40%;
left: 35%;
animation: drift-x 23s ease-in-out infinite;
}
.demo-drift-wrapper-y {
animation: drift-y 17s ease-in-out infinite;
}
.demo-drift-element {
width: 60px;
height: 60px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.6);
animation: drift-rotate 31s ease-in-out infinite;
}
Попробуйте задать длительности вроде 23s, 17s, 31s — простые числа гарантируют, что циклы совпадут нескоро.
Здесь важен технический момент. CSS не позволяет применить несколько @keyframes к одному свойству transform на одном элементе — последнее перезапишет предыдущее. Поэтому используется трюк с вложенными обёртками: каждый уровень вложенности отвечает за свою ось движения. Внешний div двигает по X, средний — по Y, внутренний — вращает. Вместе они создают сложную траекторию из простых компонентов.
Если вы попытаетесь записать несколько transform анимаций на один элемент через запятую в свойстве animation, анимации запустятся, но каждый @keyframes перезапишет значение transform предыдущего.
В результате вы увидите только последнюю анимацию. Решение — вложенные обёртки, по одной на каждую ось.
Объект пролетает целевую точку и возвращается назад — как пружина или резинка. Подпрыгивает, чуть проскакивает, ещё раз подпрыгивает, и постепенно затухает. Это придаёт анимации характер, энергию, игривость — что-то среднее между мультяшным и физическим.
Реализуется через многошаговый @keyframes, в котором объект «перелетает» через целевую точку несколько раз с уменьшающейся амплитудой. Вы задаёте промежуточные кадры вручную: допустим, элемент должен приземлиться на translateY(0), но по пути проходит через translateY(-60px), потом translateY(10px), потом translateY(-5px), и только потом останавливается.
Есть альтернатива — кастомная функция cubic-bezier(), которая позволяет создать эффект перелёта для простых переходов. Но для сложных, многофазных пружинных колебаний она не подходит — нужны ручные ключевые кадры. Генератор cubic-bezier
<div class="demo-elastic-ball"></div>
@keyframes movement-elastic {
0% {
transform: translateY(-100px);
}
/* проскочил вниз */
30% {
transform: translateY(20px);
}
/* подпрыгнул обратно */
50% {
transform: translateY(-10px);
}
/* ещё раз проскочил */
65% {
transform: translateY(5px);
}
/* почти затух */
80% {
transform: translateY(-2px);
}
/* замер */
100% {
transform: translateY(0);
}
}
.demo-elastic-ball {
position: absolute;
top: 55%;
left: 50%;
width: 50px;
height: 50px;
border-radius: 50%;
background: #fff;
transform: translateX(-50%);
animation: movement-elastic 1.5s ease-out infinite;
}
Объект движется по кругу или эллипсу — как планета вокруг звезды. Выглядит эффектно, особенно когда несколько элементов вращаются с разной скоростью. Встречается в веб-плакатах с космической, научной или абстрактной тематикой.
Самый удобный способ реализации — анимировать не сам объект, а его обёртку. Представьте невидимый рычаг, который вращается вокруг центра. На конце рычага закреплён объект. Рычаг крутится — объект описывает окружность. Технически это rotate на родительском контейнере, а дочерний элемент просто смещён от центра через translate
Есть нюанс: если на вращающемся контейнере лежит текст или изображение, оно тоже будет вращаться — и станет нечитаемым. Чтобы это исправить, на дочерний элемент навешивается контр-вращение: такое же rotate, но в обратную сторону и с той же скоростью. Объект движется по орбите, но сохраняет свою ориентацию.
<div class="demo-drift-wrapper-x">
<div class="demo-drift-wrapper-y">
<div class="demo-drift-element"></div>
</div>
</div>
@keyframes orbit-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes orbit-counter-spin {
from { transform: rotate(0deg); }
to { transform: rotate(-360deg); }
}
/* Невидимый рычаг, вращающийся вокруг центра */
.demo-orbit-arm {
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
animation: orbit-spin 6s linear infinite;
}
/* Объект, смещённый от центра вращения */
.demo-orbit-planet {
position: absolute;
width: 40px;
height: 40px;
border-radius: 50%;
background: #fff;
/* Смещение задаёт радиус орбиты */
top: -120px;
left: -20px;
/* Контр-вращение сохраняет ориентацию */
animation: orbit-counter-spin 6s linear infinite;
}
Для эллиптической орбиты добавьте transform: scaleY(0.5) на обёртку всей системы — круговое вращение сплющится в эллипс. Это проще, чем выстраивать эллиптическую траекторию через translateX и translateY с разными амплитудами.
Это один из самых выразительных паттернов для веб-плакатов, и при этом — обманчиво простой. Принцип такой: несколько одинаковых объектов получают одну и ту же анимацию, но с разными animation-duration и animation-delay. Из-за рассинхронизации зрителю кажется, что объекты двигаются хаотично, хотя каждый из них следует строго предсказуемой траектории.
Чем больше объектов — тем убедительнее иллюзия случайности. Если у восьми элементов длительности от 3s до 7s с шагом 0.5s, их паттерны совпадут заново очень нескоро, и глаз просто не успевает считать повторения. Это работает примерно как полиритмы в музыке: каждый голос прост, но вместе они создают сложную фактуру.
<div class="demo-pr-dot"></div>
<div class="demo-pr-dot"></div>
<div class="demo-pr-dot"></div>
<div class="demo-pr-dot"></div>
<div class="demo-pr-dot"></div>
<div class="demo-pr-dot"></div>
<div class="demo-pr-dot"></div>
<div class="demo-pr-dot"></div>
@keyframes pseudo-random-move {
0% { transform: translate(0, 0); }
25% { transform: translate(100px, -50px); }
50% { transform: translate(-30px, 80px); }
75% { transform: translate(60px, 20px); }
100% { transform: translate(0, 0); }
}
.demo-pr-dot {
position: absolute;
width: 16px;
height: 16px;
border-radius: 50%;
background: #fff;
animation: pseudo-random-move ease-in-out infinite alternate;
}
/* Каждый элемент получает свою длительность и позицию */
.demo-pr-dot:nth-child(1) { top: 20%; left: 10%; animation-duration: 4s; }
.demo-pr-dot:nth-child(2) { top: 60%; left: 25%; animation-duration: 5.5s; animation-delay: -1s; }
.demo-pr-dot:nth-child(3) { top: 35%; left: 55%; animation-duration: 3.5s; animation-delay: -2.5s; }
.demo-pr-dot:nth-child(4) { top: 75%; left: 70%; animation-duration: 6s; animation-delay: -0.5s; }
.demo-pr-dot:nth-child(5) { top: 15%; left: 80%; animation-duration: 4.5s; animation-delay: -3s; }
.demo-pr-dot:nth-child(6) { top: 50%; left: 45%; animation-duration: 7s; animation-delay: -1.5s; }
.demo-pr-dot:nth-child(7) { top: 80%; left: 15%; animation-duration: 5s; animation-delay: -4s; }
.demo-pr-dot:nth-child(8) { top: 40%; left: 90%; animation-duration: 3s; animation-delay: -2s; }
Обратите внимание на отрицательные animation-delay — это позволяет прокрутить анимацию в прошлое, чтобы при загрузке страницы объекты стартовали не из одной точки. Без этого приёма в первую секунду все точки синхронно дёрнутся в одну сторону, и иллюзия случайности сломается.
Попробуйте использовать не только разные длительности, но и разную прозрачность, размер, или даже слегка разные траектории через отдельные @keyframes. Чем больше параметров варьируется, тем натуральнее выглядит результат.