پرفورمنس و دسترس‌پذیری در انیمیشن؛ چیزهایی که نباید نادیده بگیرید

تا اینجا یاد گرفتیم چطور انیمیشن بسازیم، کنترلش کنیم و تنظیمش کنیم. ولی یه انیمیشن که قشنگ به نظر می‌رسه، لزوماً انیمیشن خوبی نیست. دو موضوع هست که خیلی از توسعه‌دهنده‌ها نادیده می‌گیرن: پرفورمنس (این‌که انیمیشن روون اجرا بشه، نه تکه‌تکه) و دسترس‌پذیری (این‌که برای همه‌ی کاربرها، از جمله اون‌هایی که به حرکت حساسیت دارن، مشکلی ایجاد نکنه). این آخرین درس فصله و به هردوی این‌ها می‌پردازیم.

چرا بعضی انیمیشن‌ها لگ می‌زنن ولی بعضی‌ها روون هستن؟

مرورگر برای رندر کردن هر فریم از صفحه، چند مرحله رو طی می‌کنه: Layout (محاسبه‌ی جای هر المنت)، Paint (رنگ‌آمیزی پیکسل‌ها)، و Composite (چیدن لایه‌ها روی هم). بعضی ویژگی‌های CSS وقتی تغییر می‌کنن، مرورگر رو مجبور می‌کنن این مراحل رو از اول طی کنه؛ بعضی دیگه نه.

ویژگیمرحله‌ای که فعال می‌کنههزینه
width, height, top, left, marginLayout + Paint + Compositeسنگین
background-color, box-shadow, colorPaint + Compositeمتوسط
transform, opacityفقط Compositeسبک

همین جدول دلیل اصلیه که تو تمام درس‌های قبل، تقریباً همیشه از transform و opacity برای انیمیشن استفاده کردیم، نه width یا top. وقتی مثلاً left رو انیمیت می‌کنید، مرورگر باید هر فریم دوباره چیدمان کل صفحه رو محاسبه کنه، که خیلی سنگین‌تر از جابه‌جا کردن یه لایه با translateX هست.

/* بد: باعث Layout مکرر می‌شه */
.box {
  transition: left 0.3s;
}
.box:hover {
  left: 100px;
}

/* خوب: فقط Composite */
.box {
  transition: transform 0.3s;
}
.box:hover {
  transform: translateX(100px);
}

will-change: هشدار زودهنگام به مرورگر

وقتی مرورگر از قبل بدونه که یه المنت قراره تغییر کنه، می‌تونه از قبل یه لایه‌ی جدا براش بسازه و بهینه‌سازی‌های لازم رو انجام بده، به‌جای این‌که وسط انیمیشن غافلگیر بشه:

.box {
  will-change: transform;
}

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

نکته مهم: هیچ‌وقت will-change رو به‌صورت پیش‌فرض و همیشگی روی همه‌چیز نذارید «برای احتیاط». این دقیقاً برعکس چیزیه که باید انجام بدید و پرفورمنس رو بدتر می‌کنه، نه بهتر.

prefers-reduced-motion: احترام به کاربرهایی که به حرکت حساسن

بعضی کاربرها به دلایل مختلف (مثل vestibular disorders یا سردرد میگرنی) نسبت به انیمیشن‌های زیاد یا شدید حساسیت دارن و حتی ممکنه دچار سرگیجه یا حالت تهوع بشن. سیستم‌عامل‌های مدرن (ویندوز، مک، اندروید، iOS) یه تنظیمات دارن به اسم «کاهش حرکت» که کاربر می‌تونه فعالش کنه، و CSS می‌تونه این تنظیم رو با یه media query تشخیص بده:

.box {
  animation: bounce 1s infinite;
}

@media (prefers-reduced-motion: reduce) {
  .box {
    animation: none;
  }
}

این فقط یه پیشنهاد بی‌اهمیت نیست؛ تو استانداردهای دسترس‌پذیری وب (WCAG) هم بهش اشاره شده. یه روش بهتر و کلی‌تر، به‌جای این‌که هر انیمیشن رو تک‌تک هندل کنید، اینه که از اول همه‌ی انیمیشن‌ها رو داخل یه media query بذارید:

@media (prefers-reduced-motion: no-preference) {
  .box {
    animation: bounce 1s infinite;
  }
}

این‌جوری، رفتار پیش‌فرض (بدون هیچ کاری) این می‌شه که انیمیشن اجرا نشه، مگر این‌که کاربر صراحتاً حرکت رو نبسته باشه. این روش امن‌تره چون فرض رو بر احتیاط می‌ذاره.

لازم نیست همه‌ی انیمیشن‌ها رو حذف کنید

خیلی‌ها فکر می‌کنن با فعال بودن reduced-motion باید کل انیمیشن رو خاموش کرد، ولی همیشه لازم نیست. می‌تونید به‌جای حذف کامل، فقط شدت انیمیشن رو کم کنید؛ مثلاً به‌جای یه حرکت بزرگ و پرشی، یه fade ساده و کوتاه:

.box {
  animation: bounce-big 1s infinite;
}

@media (prefers-reduced-motion: reduce) {
  .box {
    animation: fade-simple 1s infinite;
  }
}

اشتباه رایج: تست نکردن روی دستگاه ضعیف

یه انیمیشن که رو لپ‌تاپ قوی توسعه‌دهنده روون به نظر می‌رسه، ممکنه رو یه موبایل ارزون کاملاً تکه‌تکه و لگ اجرا بشه. همیشه سعی کنید انیمیشن‌های مهم رو حداقل یه بار رو یه دستگاه ضعیف‌تر یا با throttling تو DevTools تست کنید.

جمع‌بندی

برای پرفورمنس بهتر، همیشه انیمیشن رو با transform و opacity بسازید که فقط مرحله‌ی Composite رو فعال می‌کنن، نه Layout یا Paint. از will-change فقط جایی و زمانی که واقعاً لازمه استفاده کنید، نه همیشه. و برای دسترس‌پذیری، همیشه prefers-reduced-motion رو در نظر بگیرید تا کاربرهایی که به حرکت حساسن، تجربه‌ی بدی نداشته باشن. این دو موضوع، فرق بین یه انیمیشن حرفه‌ای و یه انیمیشن آماتوری رو مشخص می‌کنن.