Модуль 22

Animations та keyframes

Ось готовий урок, написаний у стилі лекцій CS50, адаптований під тему CSS Animations.


🎬 Урок: Animations та @keyframes

(Як вдихнути життя у статичний веб)


1. 🔥 Вступ: проблема та мотивація

Уявіть, що ви прийшли в театр. Ви сідаєте в крісло, відкривається завіса... і ви бачите акторів, які стоять нерухомо, як статуї. Потім світло гасне на секунду — БАХ! — і вони вже стоять в інших позах. Ще раз світло гасне — БАХ! — і головний герой вже "мертвий" на підлозі.

Чи зрозуміли ви сюжет? Напевно. Чи сподобалось вам це? Навряд чи. Це виглядає смикано, неприродно і дешево.

На жаль, саме так виглядає вебсторінка без анімацій. Елементи просто "телепортуються": була кнопка сіра — стала червона. Меню не було — хоп, і воно перекрило екран.

У реальному світі речі не телепортуються. Якщо я кину вам маркер, він летить через простір, він має швидкість, він сповільнюється, коли потрапляє вам у руку.

Питання до вас: Чому ж тоді ми змушуємо користувачів терпіти ці "телепортації" в інтерфейсах?

Сьогодні ми виправимо це. Ми навчимося не просто змінювати стилі, а режисерувати зміни в часі. Ми перетворимо "слайд-шоу" на "кіно". Ласкаво просимо у світ Animations та Keyframes.


2. 🧠 Теоретична база (без сухої академічності)

Щоб створити магію руху в CSS, нам потрібні дві речі. Уявіть це як зйомку сцени у фільмі:

  1. Сценарій (@keyframes): Що саме має відбуватися?
  2. Команда "Мотор!" (animation): Який актор це грає, як довго і в якому стилі?

📜 1. Сценарій: @keyframes

Браузер — дуже розумний, але ледачий художник. Йому не треба малювати кожен міліметр руху. Ви даєте йому лише ключові кадри (звідси й назва keyframes):

  • 0% (from): Початковий стан.
  • 100% (to): Кінцевий стан.

Браузер сам домалює все, що між ними (це називається інтерполяція).

🎬 2. Властивість animation

Просто написати сценарій мало. Він може лежати в столі. Треба призначити його конкретному елементу (наприклад, кнопці) і сказати: "Грай цю роль 2 секунди!".

Що треба знати залізно (Minimum Viable Knowledge): 1. animation-name: Ім'я вашого сценарію (@keyframes). 2. animation-duration: Скільки часу триває "вистава" (наприклад, 2s або 500ms). Без цього анімація не спрацює!

Що працює "під капотом"? Браузер бере ваші точки (наприклад, прозорість 0 і прозорість 1) і ділить час (2 секунди) на кадри (зазвичай 60 кадрів на секунду). Він перераховує значення для кожного кадру і перемальовує екран. Ваше завдання — не перевантажити його математикою (про це пізніше).


3. 🧪 Приклади (від простого до реального)

Приклад 1: "Серцебиття" (The Pulse)

Давайте зробимо коло, яке ритмічно збільшується.

Чого ви очікуєте? Коло має стати більшим, потім меншим, і так по колу.

/* 1. Сценарій */
@keyframes heartbeat {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.2); /* Збільшуємось на піку */
  }
  100% {
    transform: scale(1);   /* Повертаємось */
  }
}

/* 2. Актор */
.heart {
  width: 50px;
  height: 50px;
  background-color: red;
  border-radius: 50%;

  /* Запуск анімації */
  animation-name: heartbeat;
  animation-duration: 1s;
  animation-iteration-count: infinite; /* Нескінченно */
}

Пояснення: Ми розбили час на три етапи. Початок (нормальний), середина (великий), кінець (нормальний). infinite змушує це повторюватись вічно.


Приклад 2: "Спіннер завантаження" (Loading...)

Класика жанру. Коли дані ще не прийшли, ми показуємо колесо, що крутиться.

Чого ви очікуєте? Елемент має обертатися навколо своєї осі на 360 градусів.

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.loader {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #3498db; /* Синій верх, щоб бачити обертання */
  border-radius: 50%;

  animation: spin 1s linear infinite; 
}

Пояснення: * Ми використали скорочений запис animation. * Слово linear тут критично важливе. За замовчуванням анімації розганяються і гальмують (як потяг). Для спіннера це виглядає дивно, він має крутитися рівномірно. Тому linear.


Приклад 3: "Спливаюче повідомлення" (Toast Notification)

Уявіть, що користувач зберіг файл. Збоку виїжджає плашка "Збережено".

@keyframes slideIn {
  0% {
    transform: translateX(100%); /* Сховано за правим краєм */
    opacity: 0;
  }
  100% {
    transform: translateX(0);    /* На своєму місці */
    opacity: 1;
  }
}

.toast {
  background: #333;
  color: white;
  padding: 10px 20px;

  /* Анімація */
  animation: slideIn 0.5s ease-out forwards;
}

Пояснення: * ease-out: Починається швидко, а в кінці плавно гальмує. Це виглядає природно, ніби повідомлення "припаркувалося". * forwards: Дуже важливо! За замовчуванням після закінчення анімації елемент повертається до стану "до анімації" (зникне). forwards змушує його залишитись у стані 100%.


4. 🛠 Практична частина

Час забруднити руки кодом. Відкрийте ваш редактор (VS Code або CodePen).

Завдання 1: Світлофор Створіть div-коло. Напишіть анімацію changeColor, яка змінює колір фону: Червоний (0%) -> Жовтий (50%) -> Зелений (100%). Тривалість 3 секунди.

Завдання 2: М’ячик (Bouncing Ball) Зробіть коло, що "стрибає". * 0%: transform: translateY(0) * 50%: transform: translateY(-100px) (злетів угору) * 100%: transform: translateY(0) (впав назад) * Додайте animation-timing-function: ease-in-out для плавності.

Завдання 3: Виправ помилку Студент написав код, але квадрат не рухається. Чому?

.box {
  width: 100px; height: 100px; background: blue;
  animation-name: slideRight;
  /* Чогось не вистачає... */
}
@keyframes slideRight {
  to { transform: translateX(200px); }
}

(Підказка: Який параметр обов'язковий, щоб час пішов?)

Завдання 4: Міні-кейс "Приверни увагу" У вас є кнопка "Купити". Зробіть так, щоб вона кожні 5 секунд легенько "трусилася" (wiggle effect), нагадуючи про себе, але не дратуючи. * Підказка: Використовуйте rotate на маленькі кути (наприклад, -5deg, 5deg, -5deg, 0).

Завдання 5: А що, якщо... Що буде, якщо встановити animation-delay: -1s (від’ємне значення) для анімації, яка триває 2 секунди? Спробуйте і поясніть результат.


5. 💡 Мислення як у розробника

Ось де ми переходимо від "я вмію кодити" до "я інженер".

1. Продуктивність (FPS) — це святе

Новачки часто анімують width, height, margin, top/left. Це погано. Чому? Тому що браузеру доводиться перераховувати геометрію всього сайту (Layout/Reflow) на кожному кадрі. Це вантажить процесор. Комп'ютер починає гудіти, як літак.

Як думає про: "Я буду анімувати тільки transform (переміщення, масштаб, поворот) і opacity (прозорість)". Ці дві властивості обробляються відеокартою (GPU). Це дешево і супер-плавно.

2. Не робіть морську хворобу

Те, що ви можете змусити все на сторінці літати, не означає, що ви повинні. Анімація — це як спеції. Трохи солі — смачно. Ложка солі — їсти неможливо. Анімація має: * Або спрямовувати увагу (подивіться сюди!). * Або пояснювати зміни (меню виїхало звідси).

3. Debugging

Якщо анімація працює не так, відкрийте Chrome DevTools -> вкладка Animations (натисніть Esc -> три крапки -> Animations). Ви зможете сповільнити час до 10% швидкості і побачити, що саме йде не так.


6. 🧩 Підсумок

Отже, що ми маємо сьогодні?

  1. Ви зрозуміли, що @keyframes — це сценарій фільму, а animation — це команда режисера.
  2. Ви знаєте, що браузер сам заповнює проміжки між кадрами.
  3. Ви навчилися робити зациклені анімації (infinite) та такі, що зберігають стан (forwards).
  4. Ви (сподіваюсь) пообіцяли мені анімувати переважно transform та opacity.

Тепер ви можете створювати інтерфейси, які відчуваються живими, дихаючими та інтерактивними.

Що далі? Анімації в CSS класні, але вони "дурні" — вони просто виконуються. У наступних темах ми підключимо JavaScript, щоб запускати анімації саме тоді, коли користувач щось зробив (клікнув, проскролив, навів мишку). Це буде вже справжній інтерактив.

А поки — експериментуйте з @keyframes! Це і є CS50.