Урок 5.2: Анимации
Модуль 5 — Продвинутый CSS
transition — плавное изменение
Веб без анимаций — как машина без амортизаторов. Всё жёстко, дёргано, неприятно. transition — это самый простой способ сделать интерфейс плавным.
Когда ты меняешь свойство у элемента (например, цвет при наведении), браузер переключает его мгновенно. Transition говорит: «Эй, сделай это плавно, за 0.3 секунды».
.button {
background: #e94560;
transition: background 0.3s ease;
}
.button:hover {
background: #10b981;
}
Вот как это выглядит. Наведи мышку на квадратики — они меняются плавно:
цвет
Синтаксис transition:
/* Полный синтаксис */
transition: property duration timing-function delay;
/* Примеры */
transition: all 0.3s ease; /* всё, 0.3s, плавно */
transition: transform 0.2s ease-out; /* только transform, 0.2s */
transition: opacity 0.5s ease 0.1s; /* opacity, 0.5s, с задержкой 0.1s */
transition: background 0.3s, transform 0.2s; /* несколько свойств */
/* Отдельные свойства */
transition-property: transform;
transition-duration: 0.3s;
transition-timing-function: ease;
transition-delay: 0s;
Параметры подробно:
property— какое свойство анимировать.all— все, или конкретное:opacity,transform,background,colorи т.д.duration— длительность.0.3s(секунды) или300ms(миллисекунды). 0.2-0.3s — стандарт для интерфейсов.timing-function— как именно меняется скорость.ease(плавно),linear(равномерно),ease-in(с ускорением),ease-out(с замедлением),ease-in-out(ускорение и замедление).delay— задержка перед началом. Необязательный параметр.
transition: transform 0.2s ease и transition: opacity 0.2s ease — это самые производительные свойства для анимации. Браузер может их анимировать на видеокарте, без тормозов. А вот height и width лучше не анимировать — они дёрганые и тормозят.
transform — трансформация
transform — это свойство, которое меняет форму, размер и положение элемента. Оно не влияет на соседей (как position: relative) и отлично анимируется.
Основные функции transform:
/* Масштабирование */
transform: scale(1.5); /* увеличить в 1.5 раза */
transform: scaleX(2); /* растянуть по горизонтали */
transform: scaleY(0.5); /* сжать по вертикали */
/* Поворот */
transform: rotate(45deg); /* на 45 градусов по часовой */
transform: rotate(-90deg); /* против часовой */
/* Сдвиг */
transform: translateX(30px); /* вправо на 30px */
transform: translateY(-20px); /* вверх на 20px */
transform: translate(30px, -20px); /* по X и Y */
/* Наклон */
transform: skew(10deg); /* наклон на 10 градусов */
transform: skew(10deg, 5deg); /* по X и Y */
/* Комбинация */
transform: scale(1.2) rotate(15deg) translateX(10px);
Наведи на прямоугольники — каждый анимирует свою трансформацию:
Обрати внимание: все трансформации плавные, потому что у них есть transition: transform 0.3s. Сами по себе transform — мгновенные. Плавность даёт transition.
Очень важно: transform не вынимает элемент из потока и не влияет на соседей. Элемент трансформируется визуально, но его место в раскладке остаётся прежним. Это значит, что можно безопасно увеличивать кнопку при наведении — текст под ней не дёрнется.
transform с transition для создания ховер-эффектов. transform: scale(1.05) на кнопке при наведении — это самый простой и эффективный способ сделать интерфейс «живым».
:hover — при наведении мыши
:hover — это псевдокласс (мы уже встречались с ними в CSS). Он срабатывает, когда пользователь наводит мышку на элемент. В комбинации с transition и transform :hover творит чудеса.
/* Базовая кнопка */
.btn {
background: #e94560;
color: #fff;
padding: 14px 36px;
border: none;
border-radius: 10px;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
/* Поведение при наведении */
.btn:hover {
transform: scale(1.05);
box-shadow: 0 6px 20px rgba(233, 69, 96, 0.4);
}
/* Можно сделать эффект нажатия */
.btn:active {
transform: scale(0.97);
}
Вот кнопка с эффектом при наведении и нажатии. Попробуй навести и кликнуть:
Кнопка увеличивается при наведении и слегка сжимается при клике (:active)
Примеры эффектов для :hover:
/* Подъём карточки */
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-6px);
box-shadow: 0 12px 28px rgba(0,0,0,0.15);
}
/* Изменение цвета фона */
.nav-link {
transition: background 0.2s ease, color 0.2s ease;
}
.nav-link:hover {
background: #f0f0f0;
color: #e94560;
}
/* Подчёркивание ссылки */
.link {
text-decoration: none;
position: relative;
}
.link::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 2px;
background: #e94560;
transition: width 0.3s ease;
}
.link:hover::after {
width: 100%;
}
Последний пример — красивое подчёркивание ссылки. Оно «выезжает» слева направо при наведении. Выглядит намного интереснее, чем обычное text-decoration: underline.
🌟 Карточка
Наведи — приподнимется
🔥 Ещё карточка
С тенью и подъёмом
🌿 Третья
Hover — магия
Карточки выше имеют transition: transform 0.3s, box-shadow 0.3s. При наведении они поднимаются на 8px вверх (translateY(-8px)) и получают большую тень. Это стандартный паттерн для карточек в современных интерфейсах.
@keyframes — сложная анимация
transition хорош для простых эффектов (из точки А в точку Б). Но что, если нужно сделать сложную анимацию с несколькими этапами? Например, чтобы элемент сначала уменьшился, потом увеличился, потом изменил цвет и уехал в сторону. Для этого есть @keyframes.
@keyframes myAnimation {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.2);
opacity: 0.6;
}
100% {
transform: scale(1);
opacity: 1;
}
}
@keyframes определяет последовательность кадров (frames). 0% — начало анимации, 100% — конец. Между ними можно добавлять промежуточные точки: 25%, 50%, 75%.
Что здесь происходит:
- bounce: элемент прыгает вверх-вниз. Начало — внизу (translateY: 0), конец — вверху (translateY: -20px).
alternateозначает, что анимация идёт туда-обратно. - pulse: элемент пульсирует — увеличивается и уменьшается. 50% кадр — максимальное увеличение.
- spin: бесконечное вращение. От 0 до 360 градусов.
Вот как выглядят их keyframes в коде:
/* Прыжок */
@keyframes bounce {
0% { transform: translateY(0); }
100% { transform: translateY(-20px); }
}
/* Пульсация */
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.1);
opacity: 0.7;
}
}
/* Вращение */
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Появление слева */
@keyframes slideIn {
0% { transform: translateX(-100px); opacity: 0; }
100% { transform: translateX(0); opacity: 1; }
}
Ещё один полезный приём — анимация появления элемента на странице. Когда пользователь только открывает страницу, элементы могут плавно выезжать или проявляться. Это называется entry animation:
Анимация slideIn срабатывает один раз при загрузке
В отличие от :hover, который срабатывает по действию пользователя, @keyframes может срабатывать автоматически — при загрузке страницы, с задержкой или по триггеру через JavaScript.
animation — применить анимацию
Ты создал @keyframes — отлично. Теперь нужно применить их к элементу. Для этого есть свойство animation.
.element {
animation: spin 1.5s linear infinite;
}
/* Полный синтаксис */
animation: name duration timing-function delay iteration-count direction fill-mode play-state;
/* Примеры */
animation: bounce 0.6s ease infinite alternate;
animation: pulse 1s ease-in-out infinite;
animation: slideIn 0.5s ease-out 0.2s both; /* с задержкой 0.2s */
animation: spin 2s linear infinite, pulse 1s ease infinite; /* две анимации */
Параметры animation подробно:
| Параметр | Что делает |
|---|---|
| name | Имя @keyframes |
| duration | 0.5s или 500ms |
| timing-function | ease, linear, ease-in-out и др. |
| delay | Задержка перед стартом |
| iteration-count | Сколько раз: 1, 3, infinite |
| direction | normal, reverse, alternate, alternate-reverse |
| fill-mode | none, forwards, backwards, both |
| play-state | running, paused |
direction: normal — от 0% до 100%, reverse — от 100% до 0%, alternate — туда-обратно, alternate-reverse — обратно-туда.
fill-mode: что делать до и после анимации. forwards — остаться на последнем кадре, backwards — начать с первого кадра ещё до старта, both — и то, и другое. both удобен для entry-анимаций: элемент не показывается до анимации, потом плавно появляется и остаётся на месте.
Самые частые комбинации:
/* Бесконечное вращение (лоадер) */
.loader {
animation: spin 1s linear infinite;
}
/* Пульсирующая кнопка */
.btn-pulse {
animation: pulse 1.5s ease infinite;
}
/* Появление элемента при загрузке */
.fade-in {
animation: slideIn 0.5s ease-out both;
}
/* Анимация с задержкой для списка */
.item:nth-child(1) { animation: slideIn 0.3s ease-out 0s both; }
.item:nth-child(2) { animation: slideIn 0.3s ease-out 0.1s both; }
.item:nth-child(3) { animation: slideIn 0.3s ease-out 0.2s both; }
Последний приём — задержка для каждого элемента списка. Это создаёт эффект «волны»: элементы появляются один за другим. Выглядит очень эффектно.
Практика: кнопка, которая увеличивается при наведении, карточка с тенью
Давай сделаем страницу с несколькими анимациями. Кнопка растёт при наведении, карточка приподнимается и получает тень, а внизу — лоадер с бесконечным вращением.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Анимации в действии</title>
<style>
*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background: #f5f5f5;
margin: 0;
padding: 40px 20px;
color: #333;
}
.container {
max-width: 700px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 40px;
font-size: 2em;
}
h1 span {
display: inline-block;
animation: wave 0.6s ease infinite alternate;
transform-origin: center bottom;
}
@keyframes wave {
0% { transform: rotate(-5deg); }
100% { transform: rotate(5deg); }
}
/* Кнопка */
.btn {
display: inline-block;
padding: 16px 40px;
background: linear-gradient(135deg, #e94560, #c23152);
color: #fff;
border: none;
border-radius: 12px;
font-size: 1.1em;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.3s ease;
margin-bottom: 40px;
}
.btn:hover {
transform: scale(1.08);
box-shadow: 0 8px 24px rgba(233,69,96,0.4);
background: linear-gradient(135deg, #c23152, #a01d3a);
}
.btn:active {
transform: scale(0.96);
}
/* Карточка */
.card {
background: #fff;
border-radius: 16px;
padding: 32px;
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
transition: transform 0.3s ease, box-shadow 0.3s ease;
margin-bottom: 40px;
}
.card:hover {
transform: translateY(-8px);
box-shadow: 0 16px 40px rgba(0,0,0,0.1);
}
.card h2 {
margin: 0 0 8px;
font-size: 1.4em;
}
.card p {
color: #666;
line-height: 1.6;
margin: 0;
}
/* Список с появлением */
.items {
list-style: none;
padding: 0;
margin: 0 0 40px;
}
.items li {
background: #fff;
padding: 16px 20px;
border-radius: 10px;
margin-bottom: 8px;
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
animation: fadeInUp 0.3s ease both;
}
.items li:nth-child(1) { animation-delay: 0s; }
.items li:nth-child(2) { animation-delay: 0.1s; }
.items li:nth-child(3) { animation-delay: 0.2s; }
.items li:nth-child(4) { animation-delay: 0.3s; }
.items li:nth-child(5) { animation-delay: 0.4s; }
@keyframes fadeInUp {
0% {
opacity: 0;
transform: translateY(20px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
/* Лоадер */
.loader {
display: flex;
gap: 8px;
justify-content: center;
margin-bottom: 40px;
}
.loader .dot {
width: 16px;
height: 16px;
background: #e94560;
border-radius: 50%;
animation: dotBounce 0.6s ease infinite alternate;
}
.loader .dot:nth-child(2) { animation-delay: 0.2s; }
.loader .dot:nth-child(3) { animation-delay: 0.4s; }
@keyframes dotBounce {
0% { transform: translateY(0); }
100% { transform: translateY(-16px); background: #10b981; }
}
/* Скелетон (имитация загрузки) */
.skeleton {
display: flex;
gap: 16px;
margin-bottom: 40px;
}
.skeleton .sk-item {
flex: 1;
height: 120px;
background: linear-gradient(90deg, #e0e0e0 25%, #f5f5f5 50%, #e0e0e0 75%);
background-size: 200% 100%;
border-radius: 12px;
animation: shimmer 1.5s ease infinite;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
.center {
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<h1>
<span style="animation-delay:0s;">А</span>
<span style="animation-delay:0.1s;">н</span>
<span style="animation-delay:0.2s;">и</span>
<span style="animation-delay:0.3s;">м</span>
<span style="animation-delay:0.4s;">а</span>
<span style="animation-delay:0.5s;">ц</span>
<span style="animation-delay:0.6s;">и</span>
<span style="animation-delay:0.7s;">и</span>
</h1>
<div class="center">
<button class="btn">✨ Наведи на меня</button>
</div>
<div class="card">
<h2>📄 Карточка с тенью</h2>
<p>Наведи на меня — я приподнимусь и тень станет больше. Это эффект «подъёма» (elevation), который делает интерфейс тактильным и отзывчивым. Попробуй навести на карточку выше — она плавно приподнимается.</p>
</div>
<ul class="items">
<li>📌 Первый пункт — появляется сразу</li>
<li>📌 Второй пункт — через 0.1s</li>
<li>📌 Третий пункт — через 0.2s</li>
<li>📌 Четвёртый пункт — через 0.3s</li>
<li>📌 Пятый пункт — через 0.4s</li>
</ul>
<div class="loader">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div class="skeleton">
<div class="sk-item"></div>
<div class="sk-item"></div>
<div class="sk-item"></div>
</div>
</div>
</body>
</html>
Давай разберём каждую анимацию:
- Заголовок: каждая буква качается (
rotate(-5deg)→rotate(5deg)) с задержкой. Создаёт волну. - Кнопка:
transitionнаtransformиbox-shadow. При наведении масштабируется на 1.08, при клике — на 0.96. Плавно. - Карточка:
transitionнаtransformиbox-shadow. При наведении поднимается на 8px и тень становится больше. - Список:
@keyframes fadeInUpс разными задержками для каждого пункта. Эффект «волны». - Лоадер: три точки прыгают с задержками. Простой и красивый индикатор загрузки.
- Скелетон: имитация загрузки контента. Градиент «ездит» туда-сюда, создавая мерцание.
Давай подведём итог. Вот шпаргалка по анимациям:
/* АНИМАЦИИ — ШПАРГАЛКА */
/* 1. Плавное изменение (transition) */
.element {
transition: property 0.3s ease;
}
.element:hover {
transform: scale(1.1);
background: #10b981;
}
/* 2. Трансформации (transform) */
transform: scale(1.2); /* увеличение */
transform: rotate(45deg); /* поворот */
transform: translate(10px, 20px); /* сдвиг */
transform: skew(5deg); /* наклон */
transform: scale(1.1) rotate(10deg); /* комбо */
/* 3. Сложная анимация (@keyframes) */
@keyframes myAnim {
0% { opacity: 0; transform: translateY(20px); }
50% { opacity: 0.5; transform: translateY(-10px); }
100% { opacity: 1; transform: translateY(0); }
}
/* 4. Применение анимации (animation) */
.element {
animation: myAnim 0.5s ease-out both;
/* или покороче */
animation: pulse 1.5s ease infinite;
}
/* 5. Частые приёмы */
/* Hover-подъём карточки */
.card { transition: transform 0.3s, box-shadow 0.3s; }
.card:hover { transform: translateY(-6px); box-shadow: 0 8px 24px rgba(0,0,0,0.1); }
/* Появление элементов по очереди */
.item:nth-child(1) { animation-delay: 0s; }
.item:nth-child(2) { animation-delay: 0.1s; }
.item:nth-child(3) { animation-delay: 0.2s; }
/* Бесконечный лоадер */
@keyframes spin { 100% { transform: rotate(360deg); } }
.loader { animation: spin 1s linear infinite; }
Главное, что нужно запомнить:
transition— для простых ховер-эффектов (из А в Б)transform— изменение формы/размера/положения (производительно):hover+transition+transform— база современных интерфейсов@keyframes— для сложных многоэтапных анимацийanimation— применяет keyframes к элементу- Анимируй
transformиopacity— они самые быстрые - Не перебарщивай: анимации должны быть незаметными и тактильными, а не отвлекающими
Анимации делают интерфейс живым и отзывчивым. Пользователь чувствует, что сайт реагирует на его действия — это повышает удовольствие от использования. В следующем уроке мы разберём адаптивность — как делать сайты, которые одинаково хорошо выглядят на всех устройствах.
transition: transform 0.2s ease + :hover { transform: scale(1.1); }. Потом добавь :active { transform: scale(0.95); } — почувствуй разницу. Это занимает 2 минуты, а интерфейс становится намного приятнее.
Урок 5.2: Анимации
5 вопросов