انیمیشن پلکانیِ قابل اسکراب فقط با CSS
خلاصهٔ کاملتر
هر کسی که با CSS افکت پلکانی (staggered) ساخته باشه، یه جایی سراغ animation-delay یا transition-delay رفته: دیلی هر آیتم رو یهخرده تغییر میدی و اون افکتِ آبشاریِ قشنگ درمیاد. به گفتهٔ نویسنده این کار جواب میده ولی قابلانتقال نیست؛ نمیتونی اسکرابش کنی، به اسکرول گرهش بزنی یا به یه مقدار پیشرفتِ بیرونی وصلش کنی، چون هر المنت تو تایملاین جدای خودش زندگی میکنه.
نویسنده یه طرز فکر دیگه پیشنهاد میده: انیمیشن پلکانی رو نه بهعنوان مجموعهای از آبجکتهای مستقل با زمانبندی جدا، بلکه بهعنوان یه افکت یکپارچه و قابلپیشبینی ببینیم که با یه مقدار پیشرفتِ واحد جلو میره. اون اسم این مقدار رو میذاره m؛ یعنی پیشرفتِ کلِ انیمیشن، نه پیشرفت یه آبجکت تکی. وقتی همهچی به m وصل باشه، میتونی m رو به @keyframes، ترنزیشن، انیمیشنهای اسکرولمحور یا هر ورودیِ دیگه گره بزنی.
هستهٔ کار یه فرمول ریاضیه که نویسنده اسمش رو فرمول stagger میذاره. این فرمول m و چند دادهٔ دیگه (مثل تعداد آبجکتهایی که همزمان در حال انیمیشنان، و ترتیب هر آبجکت) رو میگیره و پیشرفت اون آبجکت خاص رو برمیگردونه. ایده اینه که یه دنبالهٔ بینهایتِ فرضی از آبجکتها رو تصور کنی که افکت از سمت چپ واردشون میشه، از آبجکتهای واقعیِ وسط رد میشه و به سمت راست میره؛ آبجکتهای سمت چپ پیشرفت 1 دارن و سمت راست 0.
نویسنده فرمول رو قدمبهقدم میسازه: اول یه دنبالهٔ صعودی از پیشرفتها درست میکنه، بعد با کم کردن از یه عددِ مرجع برعکسش میکنه تا نزولی بشه (چون آبجکتهای در حال انیمیشن از چپ به راست پیشرفتشون کم میشه)، و آخرش با clamp() مقادیر خارج از بازهٔ [0,1] رو به صفر و یک میچسبونه. برای نگاشت m به بازهٔ درست هم از درونیابی خطی (lerp) استفاده میکنه.
بخش جذاب اینه که این فرمول مستقیم به CSS پورت میشه، اون هم بهشکل قابلاستفادهٔ مجدد، با قابلیت تازهٔ @function. تابع کمکیِ --lerp که درونیابی خطی رو انجام میده اینجوریه:
@function --lerp(--a, --b, --x) {
result: calc(var(--a) + (var(--b) - var(--a)) * var(--x));
}بعد یه کاستومپراپرتی به اسم --m رو انیمیت میکنی تا انیمیشن خودکار اسکراب بشه. نکتهٔ مهم اینه که چون همهچی به --m بستهست، عوض کردن منبعِ این پیشرفت خیلی راحته:
@property --m {
syntax: "<number>";
inherits: true;
initial-value: 0;
}
@keyframes stagger-frames {
to {
--m: 1;
}
}نویسنده میگه برای جون دادن به انیمیشن میشه روی خروجی یه easing هم اعمال کرد. چون فعلاً نمیشه از cubic-bezier() یا linear() اینجا استفاده کرد، اون توابع easing رو دستی و با کمک @function و if() بازسازی میکنه (مثلاً easeInOutQuad). در آخر هم نشون میده که وصل کردن کل این انیمیشن به اسکرول فقط با دو خط کد و animation-timeline: scroll() ممکنه.
یه نکتهٔ مهم دربارهٔ پشتیبانی مرورگرها: به گفتهٔ نویسنده این قابلیتهای تازه مثل قانون @function و توابع if()، sibling-index() و sibling-count() فعلاً (تا می ۲۰۲۶) بهتر از همه تو آخرین نسخهٔ Chrome و Edge کار میکنن و پشتیبانی Firefox و Safari هنوز محدود یا غایبه.
نکات کلیدی:
- ایدهٔ اصلی: انیمیشن پلکانی رو بهجای زمان، با یه مقدار پیشرفتِ واحد (m) کنترل کن تا قابل اسکراب و وصلشدن به اسکرول بشه
- فرمول stagger پیشرفت هر آبجکت رو از روی m، تعداد آبجکتهای فعال و ترتیبشون حساب میکنه
- ساخت فرمول روی clamp() برای محدود کردن به بازهٔ [0,1] و lerp برای نگاشت تکیه داره
- قانون تازهٔ @function اجازه میده فرمول بهشکل قابلاستفادهٔ مجدد تو CSS پیاده بشه
- با animation-timeline: scroll() کل انیمیشن فقط با دو خط به اسکرول وصل میشه و هیچ JavaScriptی لازم نیست
- این قابلیتها فعلاً عمدتاً تو Chrome و Edge کار میکنن و پشتیبانی Firefox و Safari محدوده




