Sheet جدید React Aria فقط با اسکرول CSS ساخته شده
خلاصهٔ کاملتر
React Aria، کتابخونهٔ کامپوننتهای دسترسپذیر Adobe، یه کامپوننت جدید به اسم Sheet منتشر کرده. Sheet یه overlayه که از یکی از لبههای صفحه وارد میشه و کاربر میتونه با کشیدن ببندتش. از snap point، انباشتن چند sheet روی هم، حواسجمعی به کیبورد گوشی و جهتهای مختلف پشتیبانی میکنه. Devon Govett تو این پست توضیح میده که کل ماجرا روی CSS scroll snapping و view timeline ساخته شده، بالای کامپوننت Modal قبلیشون.
ترفند اصلی اینه: overlay یه المان قابل اسکرول با اسکرولبار مخفیه (scrollbar-width: none) که دو برابر ارتفاع صفحهست و فقط نیمهٔ بالاش دیده میشه. خود sheet تو نیمهٔ پایینه. وقتی بستهست، اسکرول روی صفر قرار داره و sheet بیرون از صفحهست؛ موقع باز شدن با scroll-behavior: smooth تا ۱۰۰٪ اسکرول میشه. کاربر با اسکرول به بالا اونو میبنده و وقتی IntersectionObserver ببینه کاملاً بیرون رفته، unmount میشه. یعنی حرکت انگشت بدون هیچ کد JavaScript برای touch، روی thread جدا اجرا میشه.
انیمیشنهای همگام با حرکت انگشت از view-timeline میان؛ یعنی قابلیتی که پیشرفت یه keyframe animation رو به این گره میزنه که چقدر از یه المان دیده میشه. مثلاً backdrop با کشیدن sheet کمرنگ میشه یا گوشههای sheet گرد میشن. مقدار view-timeline-inset: 0 100dvh باعث میشه انیمیشن وقتی شروع بشه که sheet واقعاً تو صفحهست:
.sheet {
view-timeline: --sheet;
view-timeline-inset: 0 100dvh;
}
.backdrop {
animation: backdrop linear both;
animation-timeline: --sheet;
}برای snapPoints به ازای هر نقطه یه div نامرئی ۱ پیکسلی داخل sheet گذاشته میشه و scroll-margin-top: 100dvh کاری میکنه که اون نقطه به پایین صفحه بچسبه. وقتی sheet نیمهبازه، محتوای داخلش با overflow: hidden قفل میشه تا کاربر از هر جایی بتونه بازش کنه؛ بعد از باز شدن کامل، overscroll-behavior: auto باعث میشه اگه بالای محتوا باشی، کشیدن به پایین sheet رو ببنده. با preventDismissal هم sheet بسته نمیشه ولی بین snap pointها جابهجا میشه.
برای روی هم افتادن چند sheet، timelineها با timeline-scope روی المان html تعریف میشن و animation-composition: accumulate اثرشون رو جمع میکنه تا عمق پشته معلوم باشه. برای کیبورد گوشی، مخصوصاً iOS که روی محتوا میاد و واحدهای dvh رو هم تغییر نمیده، به محتوای sheet یه padding-bottom به اندازهٔ اختلاف 100dvh و ارتفاع visual viewport داده میشه. هوک usePreventScroll هم بهتر شده تا موقع باز و بسته شدن کیبورد صفحه کمتر بپره. نویسنده میگه همچین چیزی چند سال پیش با CSS شدنی نبود.
نکات کلیدی:
- Sheet بالای کامپوننت Modal در React Aria ساخته شده
- حرکت کشیدن کاملاً با اسکرول بومی و CSS scroll snap پیاده شده، بدون مدیریت touch در JavaScript
- انیمیشنهای همگام با انگشت با view-timeline و prop swipeAnimation ساخته میشن
- snap pointها با div نامرئی ۱ پیکسلی و scroll-margin-top: 100dvh پیاده شدن
- انباشتن sheetها از timeline-scope و animation-composition: accumulate استفاده میکنه
- مشکل کیبورد iOS با padding-bottom بر اساس ارتفاع visual viewport حل شده




