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 پردازش میشوند و با چیدمان کاری ندارند. نتیجه: حرکت روانتر و مصرف باتری کمتر.
/* 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) هم درست کار کند:
: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 را ببینید.
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 انیمیشن را اجرا میکند:
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 در اختیار شما میگذارد. رعایتش چند خط کد است:
@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 مشکلی ایجاد نمیکند.

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