جهت حرکت، حالت پایانی، و توقف دستی؛ ظرافت‌های animation

تو درس قبل با زمان‌بندی انیمیشن آشنا شدیم: کِی شروع بشه و چند بار تکرار بشه. حالا نوبت چهار ویژگی دیگه‌ست که رفتار ظریف‌تر انیمیشن رو کنترل می‌کنن: جهت حرکتش، این‌که قبل و بعد از اجرا چه شکلی باشه، امکان مکث دستی، و منحنی سرعتش.

animation-direction: جهت اجرای انیمیشن

به‌طور پیش‌فرض، هر بار که یه انیمیشن تکرار می‌شه، از اول (0%) شروع می‌کنه و به آخر (100%) می‌ره، و اگه تکرار بشه، دوباره از همون نقطه‌ی 0% شروع می‌کنه. این مقدار پیش‌فرض، normal نام داره. اما می‌تونید این رفتار رو عوض کنید:

.box {
  animation-name: slide;
  animation-duration: 1s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}
مقداررفتار
normalپیش‌فرض؛ همیشه از 0% به 100%
reverseهمیشه از 100% به 0%
alternateیکی در میون: رفت از 0 به 100، برگشت از 100 به 0
alternate-reverseمثل alternate ولی از برگشت شروع می‌شه

alternate شاید پرکاربردترین این چهارتاست، چون باعث می‌شه حرکت رفت‌وبرگشتی و نرم به نظر برسه، به‌جای این‌که هر بار با یه پرش به نقطه‌ی شروع برگرده.

animation-fill-mode: قبل و بعد از انیمیشن چه شکلیه؟

این یکی از اون ویژگی‌هاییه که خیلی‌ها اصلاً باهاش آشنا نمی‌شن، ولی خیلی وقت‌ها باعث سردرگمی می‌شه. سؤال اینه: قبل از این‌که انیمیشن شروع بشه (مثلاً وقتی animation-delay فعاله)، و بعد از این‌که تموم می‌شه، المنت چه استایلی داره؟

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.box {
  animation-name: fade-in;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}
مقداررفتار
noneپیش‌فرض؛ المنت قبل و بعد از انیمیشن به استایل اصلی خودش (نه چیزی از keyframe) برمی‌گرده
forwardsبعد از پایان انیمیشن، مقدار آخرین keyframe (100%) حفظ می‌شه
backwardsدر طول animation-delay، مقدار اولین keyframe (0%) از همون ابتدا اعمال می‌شه
bothترکیب forwards و backwards؛ هم قبل، هم بعد

مثال fade-in بالا رو در نظر بگیرید: بدون forwards، به محض تموم شدن انیمیشن، opacity المنت به مقدار اصلیش (که احتمالاً 1 هست، چون تو CSS معمولی جایی opacity رو صفر نذاشتیم) برمی‌گرده؛ یعنی هیچ فرقی حس نمی‌شه. اما با forwards، مقدار opacity: 1 که تو keyframe نوشته شده، بعد از پایان انیمیشن هم می‌مونه.

نکته مهم: اگه یه المنت قراره با delay ظاهر بشه و می‌خواید تا قبل از شروع انیمیشن هم نامرئی باشه (نه این‌که یهو تو delay دیده بشه و بعد محو بشه)، حتماً از backwards یا both استفاده کنید.

animation-play-state: مکث و ادامه‌ی دستی

این ویژگی بهتون اجازه می‌ده انیمیشن رو با CSS (مثلاً روی هاور، یا با تغییر کلاس از طریق جاوااسکریپت) متوقف یا از سر گرفت:

.spinner {
  animation-name: rotate;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-play-state: running;
}

.spinner:hover {
  animation-play-state: paused;
}

مقدار پیش‌فرض running هست. وقتی به paused تغییرش بدید، انیمیشن دقیقاً همون‌جایی که بود متوقف می‌شه، نه این‌که به عقب برگرده. این خیلی برای موقعیت‌هایی مثل «کاربر روی یه انیمیشن هاور می‌کنه و می‌خواد دقیق‌تر ببینتش» کاربرد داره.

animation-timing-function: منحنی سرعت

این ویژگی همون مفهومیه که تو transition هم دیدیم؛ مشخص می‌کنه سرعت تغییر بین keyframe ها چطور توزیع بشه؛ خطی، یا با شتاب و کاهش شتاب:

.box {
  animation-name: bounce;
  animation-duration: 1s;
  animation-timing-function: ease-in-out;
}

مقادیر رایجش ease (پیش‌فرض)، linear، ease-in، ease-out، ease-in-out و cubic-bezier() هستن. یه نکته‌ی مهم که خیلی وقت‌ها نادیده گرفته می‌شه: وقتی این ویژگی رو مستقیم روی خود انیمیشن (نه روی هر keyframe جدا) می‌نویسید، همون منحنی برای تمام مراحل انیمیشن یکسان اعمال می‌شه. اگه بخواید هر بخش از انیمیشن منحنی سرعت متفاوتی داشته باشه، باید animation-timing-function رو داخل خود یکی از درصدهای keyframe بنویسید:

@keyframes bounce {
  0% {
    transform: translateY(0);
    animation-timing-function: ease-out;
  }
  50% {
    transform: translateY(-30px);
    animation-timing-function: ease-in;
  }
  100% {
    transform: translateY(0);
  }
}

این‌جوری، حرکت رفتن به بالا با یه منحنی و برگشتن به پایین با منحنی دیگه‌ای اجرا می‌شه؛ چیزی که حس واقعی‌تری از حرکت طبیعی (مثل زمین خوردن یه توپ) می‌ده.

جمع‌بندی

animation-direction تعیین می‌کنه هر تکرار از کدوم سمت شروع بشه (با گزینه‌ی محبوب alternate برای حرکت رفت‌وبرگشتی)، animation-fill-mode مشخص می‌کنه قبل و بعد از اجرا چه استایلی اعمال بشه (که forwards و both پرکاربردترین‌ها هستن)، animation-play-state امکان مکث و ادامه‌ی دستی رو می‌ده، و animation-timing-function منحنی سرعت رو کنترل می‌کنه؛ چه یکسان برای کل انیمیشن، چه جداگانه برای هر مرحله.