فرانت اند

انیمیشن‌های روان با CSS و JavaScript

انیمیشن خوب بی‌صدا کار می‌کند: توجه را هدایت می‌کند و کسی متوجه وجودش نمی‌شود. انیمیشن بد یا ۱۵ فریم در ثانیه می‌دود یا مخاطب را اذیت می‌کند. اینجا نشان می‌دهیم انیمیشن‌های روان با CSS و JavaScript را چطور بسازید و چه موقع کدام ابزار را انتخاب کنید.

  • نویسنده تیم تتا
  • ۸ دقیقه مطالعه
  • به‌روزرسانی:
انیمیشن‌های روان با CSS و JavaScript

CSS، Web Animations یا requestAnimationFrame؟

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

مقایسه‌ی روش‌های انیمیشن
ابزارمناسب برایمحدودیت
transitionتغییر بین دو حالت (hover، باز و بسته‌شدن)فقط دو نقطه‌ی شروع و پایان
@keyframesحرکت چندمرحله‌ای و تکرارشونده (لودینگ، pulse)کنترل پویا سخت‌تر است
Web Animations APIشروع، توقف و مقدار پویا از JavaScriptکد بیشتر از CSS
requestAnimationFrameفیزیک سفارشی، بوم (canvas)، جلوه‌ی وابسته به اسکرولمدیریت دستی فریم و پاک‌سازی

برای بیشتر سایت‌های شرکتی و فروشگاهی، CSS به‌اضافه‌ی چند خط JavaScript برای افزودن کلاس کافی است. سراغ کتابخانه‌ای مثل GSAP فقط وقتی بروید که زمان‌بندی پیچیده‌ی چند عنصر دارید.

چرا فقط transform و opacity؟

مرورگر برای هر فریم سه مرحله دارد: محاسبه‌ی چیدمان (layout)، رنگ‌آمیزی (paint) و ترکیب لایه‌ها (composite). تغییر width، top یا margin هر سه مرحله را روی کل بخش‌های اثرپذیر تکرار می‌کند. اما transform و opacity معمولاً فقط در مرحله‌ی ترکیب و اغلب روی GPU پردازش می‌شوند و با چیدمان کاری ندارند. نتیجه: حرکت روان‌تر و مصرف باتری کمتر.

css
/* Slow: triggers layout on every frame */
.card:hover { margin-top: -8px; }

/* Fast: composite-only */
.card { transition: transform 250ms ease, box-shadow 250ms ease; }
.card:hover { transform: translateY(-8px); }

اگر بخشی از رابط‌تان چیدمان واقعی را عوض می‌کند (مثل آکاردئون)، تغییر ارتفاع ناگزیر است؛ آن را کوتاه نگه دارید و عنصرهای اطراف را ساده کنید. جزئیات ساخت چیدمان‌ها در راهنمای CSS Grid آمده است.

تصویر انتزاعی از اشکال رنگی که روی مسیرهای نورانی نرم و پیوسته حرکت می‌کنند
حرکت روان یعنی کار کمتر برای مرورگر؛ فقط ویژگی‌های ارزان را تغییر دهید.

زمان‌بندی و easing

مدت و منحنی حرکت بیشتر از نوع افکت در حس «حرفه‌ای‌بودن» اثر دارد. چند قاعده‌ی تجربی که در پروژه‌هایمان استفاده می‌کنیم:

  • بازخورد کوچک (hover، فشردن دکمه): ۱۰۰ تا ۲۰۰ میلی‌ثانیه.
  • باز و بسته‌شدن منو یا مودال: ۲۰۰ تا ۳۵۰ میلی‌ثانیه.
  • ورود عنصر به صفحه از ease-out و خروج از ease-in استفاده کند؛ linear فقط برای حرکت‌های پیوسته مثل چرخش لودینگ.
  • انیمیشن‌های طولانی‌تر از ۵۰۰ میلی‌ثانیه برای کنش‌های پرتکرار کاربر را کوتاه کنید؛ کندی را کاربر حس می‌کند.

یک نکته‌ی ویژه برای سایت‌های فارسی: انیمیشن اسلاید جانبی باید جهت‌دار باشد. اگر منو از راست باز می‌شود، مقدار translateX را ثابت نگذارید؛ از ویژگی‌های منطقی یا یک متغیر جهت استفاده کنید تا نسخه‌ی انگلیسی (LTR) هم درست کار کند:

css
:root { --dir: 1; }
[dir="rtl"] { --dir: -1; }

.drawer { transform: translateX(calc(100% * var(--dir))); transition: transform 300ms ease-out; }
.drawer.open { transform: translateX(0); }

Web Animations API برای کنترل با JavaScript

وقتی نیاز دارید انیمیشن را از کد شروع، متوقف، برعکس یا با مقدار پویا اجرا کنید، element.animate() بهترین نقطه‌ی میانی بین CSS و حلقه‌ی دستی است: همان کارایی CSS را دارد و یک شیء Animation با وعده‌ی finished برمی‌گرداند. پشتیبانی آن در مرورگرهای امروزی گسترده است؛ برای جزئیات مستندات MDN را ببینید.

js
const toast = document.querySelector('.toast');

const anim = toast.animate(
  [
    { opacity: 0, transform: 'translateY(16px)' },
    { opacity: 1, transform: 'translateY(0)' }
  ],
  { duration: 250, easing: 'ease-out', fill: 'forwards' }
);

// Run code only after the animation completes
anim.finished.then(() => setTimeout(() => toast.remove(), 3000));

نمایش هنگام اسکرول با IntersectionObserver

برای افکت «ظاهر شدن هنگام رسیدن به عنصر» از مدیریت رویداد scroll استفاده نکنید؛ IntersectionObserver بدون فشار به نخ اصلی همین کار را می‌کند و CSS انیمیشن را اجرا می‌کند:

js
const io = new IntersectionObserver((entries) => {
  entries.forEach(e => {
    if (e.isIntersecting) {
      e.target.classList.add('is-visible');
      io.unobserve(e.target); // animate once
    }
  });
}, { threshold: 0.15 });

document.querySelectorAll('.reveal').forEach(el => io.observe(el));

دسترس‌پذیری: حرکت کمتر برای کسانی که می‌خواهند

حرکت زیاد برای بعضی افراد (مثلاً با اختلال‌های دهلیزی یا میگرن) ناخوشایند و حتی آسیب‌زاست. سیستم‌عامل‌ها گزینه‌ی «کاهش حرکت» دارند و CSS آن را با prefers-reduced-motion در اختیار شما می‌گذارد. رعایتش چند خط کد است:

css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

همچنین انیمیشن‌های خودکار و تکرارشونده‌ای که بیش از پنج ثانیه ادامه دارند باید قابل توقف باشند. بقیه‌ی موارد مرتبط را در چک‌لیست دسترس‌پذیری وب مرور کنید.

عیب‌یابی و چک‌لیست

اگر انیمیشنی «پرش» دارد، تب Performance در DevTools را باز کنید و فریم‌های قرمز را ببینید؛ معمولاً یک Layout یا Paint سنگین در وسط حرکت است. تیک «Paint flashing» در بخش Rendering هم نشان می‌دهد چه چیزی بازرنگ‌آمیزی می‌شود. انیمیشن‌هایی که ظاهر صفحه را در لحظه‌ی بارگذاری جابه‌جا می‌کنند ممکن است CLS را هم خراب کنند؛ شاخص‌ها را در راهنمای Core Web Vitals ببینید.

  • فقط transform و opacity انیمیت می‌شوند؟
  • مدت و easing برای نوع حرکت مناسب است؟
  • جهت حرکت در RTL و LTR درست است؟
  • prefers-reduced-motion رعایت شده است؟
  • will-change فقط موقت و روی عنصر لازم است؟

برای ساخت رابط‌های متحرک و سریع در پروژه‌ی خودتان، از خدمات توسعه‌ی وب ما کمک بگیرید یا نمونه‌هایمان را در نمونه‌کارها ببینید.

پرسش‌های متداول

انیمیشن CSS بهتر است یا JavaScript؟

برای حالت‌های ساده مثل hover و باز و بسته‌شدن، CSS ساده‌تر و بهینه‌تر است. وقتی کنترل برنامه‌نویسی‌شده، توقف، یا مقدار پویا لازم دارید، Web Animations API یا یک کتابخانه مناسب‌تر است.

چرا انیمیشن من روی موبایل پرش دارد؟

معمولاً ویژگی‌هایی مثل width، top یا box-shadow سنگین انیمیت شده‌اند و باعث layout یا paint در هر فریم می‌شوند. به transform و opacity تغییر دهید و در DevTools تب Performance را بررسی کنید.

انیمیشن چقدر باید طول بکشد؟

برای بازخورد کوچک ۱۰۰ تا ۲۰۰ میلی‌ثانیه و برای منو و مودال ۲۰۰ تا ۳۵۰ میلی‌ثانیه معمولاً مناسب است. حرکت‌های طولانی‌تر در کنش‌های پرتکرار، رابط را کند نشان می‌دهند.

آیا انیمیشن به سئو آسیب می‌زند؟

خود انیمیشن نه، ولی اگر جاوااسکریپت سنگین یا جابه‌جایی چیدمان بسازد، سرعت و CLS بدتر می‌شود و رتبه و تجربه‌ی کاربری آسیب می‌بیند. انیمیشن سبک و مبتنی بر transform مشکلی ایجاد نمی‌کند.

دیدگاه‌ها

    هنوز دیدگاهی ثبت نشده است. اولین نفر باشید.

    دیدگاه‌ها پس از بررسی منتشر می‌شوند.