Scroll-driven Animations اجازه میدهد پیشرفت انیمیشن به موقعیت اسکرول وابسته باشد. مثلاً یک نوار با پایین رفتن صفحه بلندتر میشود و با برگشتن کاربر کوتاهتر. این رفتار با انیمیشنی که فقط هنگام ورود عنصر شروع میشود فرق دارد؛ در حالت دوم، زمان معمولی اجرای انیمیشن را جلو میبرد. عنوان قبلی این مقاله از نهایی شدن استاندارد حرف میزد، اما سند منتشرشدهٔ W3C که در این بازنویسی بررسی شد، Working Draft است. وضعیت سند و پشتیبانی مرورگر دو موضوع جدا هستند.
CSS برای بعضی از این رفتارها مسیر مستقیم فراهم کرده است، ولی نتیجهٔ آن تضمین شصت فریم در ثانیه روی هر دستگاه نیست. اندازهٔ صفحه، ویژگی متحرک، تعداد عناصر و کارهای دیگر مرورگر در تجربه اثر دارند. ادعای قبلی دربارهٔ عملکرد تضمینشده حذف شده است. بهتر است یک مثال کوچک بسازیم و دقیق بگوییم چه رفتار و چه fallbackی دارد؛ سپس برای استفاده در محصول، نیاز و محیط مخاطب را جدا بررسی کنیم.
دو timeline با دو سؤال متفاوت
Scroll Progress Timeline به موقعیت اسکرول یک کانتینر مربوط است. برای نوار پیشرفت کل صفحه، این رابطه طبیعی است: ابتدای مسیر اسکرول یک سر انیمیشن و انتهای مسیر سر دیگر آن است. View Progress Timeline به عبور یک عنصر از محدودهٔ دید مربوط میشود. اگر کارت باید هنگام نزدیک شدن به viewport کمی تغییر ظاهر بدهد، موضوع از نوع دوم است. اشتباه گرفتن این دو باعث میشود اثر به والد یا عنصر نامناسب وصل شود.
برای انتخاب، رفتار مورد نظر را با جملهٔ ساده بنویسید. «نوار با پیمودن کل صفحه رشد کند» یک قرارداد روشن است. «کارت وقتی وارد دید میشود ظاهر شود» به تعیین محدودهٔ ورود نیاز دارد. «صفحه سینمایی باشد» قرارداد فنی قابل اجرا نیست. هرچه جملهٔ رفتار دقیقتر باشد، انتخاب timeline و محدودهٔ انیمیشن کمتر به آزمون تصادفی مقدارها وابسته میشود. توضیح محصول باید پیش از نوشتن keyframes معلوم باشد.
نمونهٔ کامل نوار پیشرفت اسکرول
نمونهٔ زیر یک فایل مستقل HTML است. آن را به نام scroll-progress.html ذخیره کنید و باز کنید. هیچ package، JavaScript، تصویر یا فایل CSS خارجی لازم ندارد. سه بخش محتوایی، طول صفحه را برای مشاهدهٔ اسکرول ایجاد میکنند. این بخشها متن آموزشی همین نمونهاند؛ در محصول نباید برای فعال شدن یک جلوه، فضای خالی بیدلیل به مقاله اضافه کرد. نوار نیز تزئینی است و اطلاعات اصلی صفحه بدون آن قابل خواندن میماند.
<!doctype html>
<html lang="fa" dir="rtl">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>نوار پیشرفت اسکرول</title>
<style>
body{font-family:system-ui;line-height:1.9;margin:0;color:#17213a;background:#f8fafc}
main{max-width:42rem;margin:auto;padding:3rem 1.5rem}
section{min-height:75vh;padding-block:2rem}
.progress-strip{display:none;position:fixed;inset:0 0 auto;height:5px;background:#2447a8;transform-origin:right center;z-index:1}
@keyframes progress{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@supports (animation-timeline:scroll(root block)) {
.progress-strip{display:block;animation:progress 1s linear both;animation-timeline:scroll(root block)}
}
@media (prefers-reduced-motion:reduce){.progress-strip{display:none}}
</style>
<div class="progress-strip" aria-hidden="true"></div>
<main>
<h1>مشاهده موقعیت اسکرول</h1>
<section><h2>شروع</h2><p>این نوار فقط موقعیت صفحه را نشان میدهد و اندازهگیری خواندن نیست.</p></section>
<section><h2>میانه</h2><p>با برگشتن به بالا، اندازه نوار نیز به موقعیت قبلی برمیگردد.</p></section>
<section><h2>پایان</h2><p>متن بدون قابلیت انیمیشن نیز در دسترس است.</p></section>
</main>
</html>
عنصر progress-strip در HTML وجود دارد و تمام selectorهای CSS به عناصر همان فایل اشاره میکنند. خط پایهٔ نمونه نوار را مخفی نگه میدارد. فقط اگر مرورگر مقدار animation-timeline مورد استفاده را تشخیص دهد، نوار نمایش داده میشود. بنابراین محیطی که قابلیت را ندارد، نوار ثابت و گمراهکنندهای نمیبیند. محتوای صفحه در هر دو حالت یکسان است و کاربر برای رسیدن به متن وابسته به اجرای انیمیشن نمیشود.
در keyframes فقط scaleX تغییر میکند. عرض منطقی نوار ثابت میماند و رشد با transform انجام میشود. مبدأ transform در این نمونه از سمت راست انتخاب شده تا حرکت با ترکیب فارسی صفحه هماهنگ باشد. اگر همان نمونه به صفحهٔ چپبهراست منتقل شد، مبدأ رشد نیز باید با تصمیم طراحی آن صفحه هماهنگ شود. تغییر dir بهتنهایی همهٔ تصمیمهای جهت در CSS فیزیکی را اصلاح نمیکند؛ right center یک انتخاب صریح است.
ترتیب declarationها اهمیت دارد
ویژگی animation یک shorthand است و ممکن است تنظیمهای مرتبط را بازنشانی کند. در نمونه، animation-timeline بعد از آن نوشته شده است. اگر در بازنویسی CSS، این ترتیب جابهجا شود، timeline مورد انتظار ممکن است از دست برود. وقتی مثال را به stylesheet بزرگ منتقل میکنید، فقط نزدیکترین rule را نبینید؛ rule دیگری که animation را دوباره تنظیم میکند نیز بر نتیجه اثر میگذارد. مشکل همیشه از عدم پشتیبانی مرورگر نیست.
مرجع animation-timeline نحو و جدول سازگاری را نشان میدهد. در گزارش پروژه، مقدار واقعی استفادهشده را ثبت کنید. پشتیبانی از یک property به معنی پشتیبانی یکسان از همهٔ syntaxها و رفتارهای مرتبط نیست. بررسی قابلیت نمونه را با همان رفتار مورد نیاز انجام دهید. در این مقاله هیچ ادعای اجرای آزمون مرورگر یا اندازهگیری فریم مطرح نشده است؛ کد و توضیح برای مرور تحریری کنار هم آماده شدهاند.
پیشرفت اسکرول همان پیشرفت خواندن نیست
نوار نمونه موقعیت صفحه را نشان میدهد، نه اینکه کاربر چه مقدار از متن را فهمیده یا خوانده است. کسی میتواند با یک حرکت به انتها برود و همهٔ نوار پر شود. اگر صفحه footer بزرگ، نظرها یا پیشنهاد مقاله دارد، سهم آنها هم در طول مسیر اسکرول اثر میگذارد. بنابراین برچسب «شما تمام مقاله را خواندید» بر اساس این نوار دقیق نیست. برای یک نشانهٔ بصری ساده، نام «پیشرفت اسکرول» معنای روشنتری دارد.
اگر هدف، پیمودن فقط بدنهٔ مقاله است، محدودهٔ اثر باید مطابق همان بدنه تعریف شود. اضافه شدن تبلیغ یا باز شدن بخش توضیحات میتواند طول محتوا را تغییر دهد. طراحی باید مشخص کند کاربر با چه نشانهای مواجه میشود و آیا تغییر آن نشانه در میانهٔ مطالعه قابل قبول است. این موضوع صرفاً تنظیم درصد نیست؛ قرارداد معنایی نوار است. هرچه ادعای رابط کوچکتر و دقیقتر باشد، احتمال برداشت غلط کمتر میشود.
محتوا را برای انیمیشن پنهان نکنید
در نمونههای fade-in گاهی opacity اولیهٔ عناصر صفر میشود و فرض میشود انیمیشن همیشه اجرا خواهد شد. اگر قابلیت پشتیبانی نشود یا rule دیگری آن را مختل کند، متن اصلی ممکن است ناپدید بماند. طراحی امنتر این است که حالت عادی، محتوا را نشان دهد و تغییر نمایشی فقط در محدودهٔ قابلیت فعال شود. حتی در حالت فعال نیز بهتر است ورود کمرنگ، خواندن اطلاعات اصلی را به تأخیر نیندازد؛ مخصوصاً برای عنوانها و کنترلهای ضروری.
حرکت نباید جای نشانهٔ وضعیت را بگیرد. اگر کاربر عملیاتی انجام داده و نتیجه باید معلوم باشد، متن وضعیت مستقل لازم است. یک کارت که با اسکرول تغییر رنگ میدهد، لزوماً تأیید عملیات نیست. جدا نگه داشتن معنای حرکت از معنای وضعیت به تیم محتوا هم کمک میکند؛ نویسنده میداند چه چیزی را باید توضیح دهد و چه چیزی فقط بخشی از ظاهر است. برای ادامه، بحث Microinteractions و UX همین رابطه را در تعاملهای کوچک بررسی میکند.
کاهش حرکت بخشی از قرارداد نمونه است
در media query مربوط به prefers-reduced-motion، نوار نمونه مخفی میشود. این انتخاب برای یک عنصر تزئینی کافی است، چون حذف آن اطلاعات لازم را از کاربر نمیگیرد. اگر حرکت، اطلاعات واقعی منتقل میکرد، باید نمایش ثابت یا جایگزین متنی طراحی میشد. تفاوت این دو موقعیت را در تصمیم تیم ثبت کنید. خاموش کردن همهٔ عناصر متحرک بدون توجه به نقششان، ممکن است در یک محصول دیگر بخشی از اطلاعات را نیز حذف کند.
Parallax بزرگ یا جابهجایی مستمر کل محتوا ممکن است برای بعضی کاربران آزاردهنده باشد. کوچک کردن دامنهٔ حرکت و محدود کردن آن به یک جزء، معمولاً خواندن صفحه را کمتر تحت تأثیر میگذارد. این توصیه یک حکم ثابت دربارهٔ همهٔ برندها نیست؛ تصمیم باید با نقش صفحه و نیاز مخاطب هماهنگ شود. یک راهنمای استفاده یا فرم حساس، اولویت متفاوتی از صفحهٔ نمایش یک اثر هنری دارد و نباید نسخهٔ حرکت یکسانی بگیرد.
کارایی را به ویژگی متحرک وصل کنید
انتخاب transform در این مثال برای پرهیز از تغییر مداوم چیدمان است، ولی از آن نمیتوان تضمین عملکرد استخراج کرد. اگر صدها عنصر، سایههای سنگین و محتوای پیچیده همزمان متحرک شوند، تجربهٔ دستگاه ضعیف ممکن است متفاوت باشد. تعداد عناصر و دامنهٔ اثر را با هدف صفحه تناسب دهید. حذف listener اسکرول JavaScript تنها یک بخش از کار است؛ هزینهٔ رنگآمیزی و ترکیب نهایی صفحه همچنان در مرورگر وجود دارد.
برای انتقال نمونه به محصول، ابتدا fallback و حالت کاهش حرکت را در قرارداد نگه دارید. سپس مشخص کنید timeline به کل صفحه یا یک کانتینر داخلی مربوط است و کنترلهای ثابت کجا قرار دارند. اگر نوار بالای صفحه با header برخورد دارد، جای آن را در چیدمان حل کنید. افزودن z-index بزرگ بدون شناخت لایهها ممکن است مشکل دیگری بسازد. رفتار کوچک و قابل توضیح، نگهداری این قابلیت را از مجموعهای از افکتهای نامرتبط سادهتر میکند.
هنوز دیدگاهی ثبت نشده
اولین نفری باشید که نظر میدهد!