ساختن نشانگر پیشرفت پیمایش

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

نحوه پیاده‌سازی

برای ایجاد نشانگر پیشرفت پیمایش، به دو چیز نیاز دارید:

  1. عنصری که به‌عنوان نوار پیشرفت عمل می‌کند. این عنصر معمولاً position: fixed یا position: absolute است تا وقتی کاربر پیمایش می‌کند در دید باقی بماند.
  2. پویانمایی‌ای که به موقعیت پیمایش پیوند داده شده است.

از این طریق می‌توانید به این هدف برسید:

  • ابتدا، یک عنصر HTML ایجاد کنید که به‌عنوان نوار پیشرفت شما عمل کند. این عنصر را می‌توانید مطابق میل خودتان سبک‌بندی کنید.
  • سپس، در CSS خود، یک پویانمایی @keyframes تعریف کنید که نوار پیشرفت را مقیاس‌بندی کند. یک رویکرد رایج، مقیاس‌بندی عنصر از scaleX(0) به scaleX(1) است.
  • درنهایت، این پویانمایی را روی عنصر نوار پیشرفت اعمال کنید و animation-timeline آن را روی scroll-timeline تنظیم کنید. این به مرورگر می‌گوید که پیشرفت پویانمایی را براساس موقعیت پیمایش نزدیک‌ترین پیمایشگر اجدادی هدایت کند.

کد نمونه

این کد عنصر #progress را در پیمایش بااستفاده از یک خط زمان پیمایش ناشناس که توسط تابع scroll() ایجاد شده است، رشد می‌دهد.

@media (prefers-reduced-motion: no-preference) {
  @supports ((animation-timeline: scroll())) {
    @keyframes grow-progress {
      from { transform: scaleX(0); }
      to { transform: scaleX(1); }
    }

    #progress {
      position: fixed;
      left: 0; top: 0;
      width: 100%; height: 1em;
      background: red;

      transform-origin: 0 50%;
      animation: grow-progress auto linear;
      animation-timeline: scroll();
    }
  }
}

به‌دلیل مکان آن در DOM، تابع scroll() نزدیک‌ترین پیمایشگر جد خود را در جهت block ردیابی می‌کند که در اینجا پیمایشگر ریشه است.

<body>
  <!-- MANDATORY: Purely decorative visual scroll progress bars MUST set aria-hidden="true" to remove the empty element from the assistive technology reading tree -->
  <div id="progress" aria-hidden="true"></div>
</body>

این کد عنصر #progress را در پیمایش بااستفاده از یک خط زمان پیمایش نام‌گذاری‌شده که توسط ویژگی scroll-timeline ایجاد شده است، رشد می‌دهد.

@media (prefers-reduced-motion: no-preference) {
  @supports ((animation-timeline: scroll())) {
    @keyframes grow-progress {
      from { transform: scaleX(0); }
      to { transform: scaleX(1); }
    }

    :root {
      scroll-timeline: --tl block;
    }

    #progress {
      position: fixed;
      left: 0; top: 0;
      width: 100%; height: 1em;
      background: red;

      transform-origin: 0 50%;
      animation: grow-progress auto linear;
      animation-timeline: --tl;
    }
  }
}

روال‌های مطلوب

هنگام استفاده از پویانمایی‌های پیمایش‌محور، مهم است که چند روال مطلوب را دنبال کنید تا تجربه‌ای روان و دسترس‌پذیر را تضمین کنید:

  • باید تشخیص ویژگی را اضافه کنید: همه مرورگرها از پویانمایی‌های پیمایش‌محور پشتیبانی نمی‌کنند. از @supports (animation-timeline: scroll()) برای بررسی پشتیبانی و ارائه بازگشت به روش پیش‌فرض برای مرورگرهایی که از آن پشتیبانی نمی‌کنند استفاده کنید.
    • از بسته scroll-timeline-polyfill برای راهبرد جایگزین استفاده نکنید زیرا ویژگی‌های آن کامل نیست و مشکلات شناخته‌شده زیادی دارد.
    • اگر پویانمایی فقط تزئینی درنظر گرفته می‌شود، «ارتقای پیش‌رو» را انتخاب کنید و گزینه جایگزین ارائه ندهید.
  • باید عناصر صرفاً تزئینی را از جریان‌های خواندن فناوری کمکی بردارید: aria-hidden="true" را برای نشانگرهای پیمایش صرفاً دیداری اعمال کنید تا مطمئن شوید صفحه‌خوان‌ها با گره‌های خالی و بی‌نام مواجه نمی‌شوند.
  • باید به اولویت‌های کاربر احترام بگذارید: برخی‌از کاربران ترجیح می‌دهند حرکت کمتری در وب داشته باشند. از پُرسمان رسانه prefers-reduced-motion برای غیرفعال کردن یا کاهش پویانمایی‌ها برای این کاربران استفاده کنید.
  • باید سعی کنید فقط دارایی‌های CSS کارا را پویانمایی کنید: برای داشتن روان‌ترین پویانمایی‌ها، فقط دارایی‌هایی را پویانمایی کنید که رشته ترکیب‌کننده مرورگر می‌تواند آن‌ها را مدیریت کند، مثل transform و opacity. پویانمایی کردن ویژگی‌های دیگر مثل width یا height می‌تواند به مشکلات عملکردی منجر شود.
  • باید از ترتیب صحیح اعلام استفاده کنید: هنگام استفاده از ویژگی خلاصه animation، animation-timeline را بعداز آن اعلام کنید تا از بازنشانی خط زمان توسط خلاصه جلوگیری شود.

هنگام استفاده از تابع scroll() برای ایجاد پویانمایی پیمایش‌محور:

  • اختیاری درباره پیمایشگر صریح باشید: وقتی نزدیک‌ترین پیمایشگر جد را هدف قرار نمی‌دهید، درباره اینکه می‌خواهید از کدام پیمایشگر با scroll(root) یا scroll(self) استفاده کنید صریح باشید.
    • وقتی root، nearest، یا self کافی نیستند، از scroll-timeline نام‌گذاری‌شده استفاده کنید.
  • اختیاری به‌طور صریح محور موردنظر برای ردیابی را مشخص کنید: وقتی محور پیش‌فرض block را هدف قرار نمی‌دهید (مثلاً در پیمایشگر افقی)، به‌طور صریح مشخص کنید که کدام محور باید با scroll(block) یا scroll(inline) ردیابی شود.

هنگام استفاده از ویژگی scroll-timeline برای ایجاد پویانمایی پیمایش‌محور:

  • باید از CSS <dashed-ident> برای نام استفاده کنید.
  • اختیاری محور موردنظر برای ردیابی را به‌طور صریح مشخص کنید: وقتی محور پیش‌فرض block را هدف قرار نمی‌دهید (مثلاً در پیمایشگر افقی)، به‌طور صریح مشخص کنید که کدام محور با scroll-timeline-axis ردیابی شود.
  • باید مطمئن شوید که دامنه جستجو کار می‌کند: وقتی عنصری که scroll-timeline را اعلام می‌کند، جد درخت مسطح عنصر پویانمایی‌شده نیست، بااستفاده از timeline-scope در جد مشترک، نمایان بودن نام scroll-timeline را بالا ببرید.

راهبردهای جایگزین

برای مرورگرهایی که از پویانمایی‌های پیمایش‌محور پشتیبانی نمی‌کنند، می‌توانید از یک جایگزین برای بازآفرینی جلوه‌های دیداری استفاده کنید. جایگزین‌ها معمولاً با شنونده پیمایش (برای جلوه‌های ScrollTimeline) یا IntersectionObserver API (برای جلوه‌های ViewTimeline) ساخته می‌شوند.

در مرورگرهایی که پشتیبانی داخلی از پویانمایی‌های پیمایش‌محور دارند، همیشه از پیاده‌سازی CSS بومی استفاده کنید زیرا عملکرد بهتری دارند.

توجه داشته باشید که همه جلوه‌ها را نمی‌توان بااستفاده از رویکرد جایگزین بازآفرینی کرد.

به‌طور خاص برای این مورد استفاده، دستورگان زیر برای مرورگرهایی که از پویانمایی‌های پیمایش‌محور پشتیبانی نمی‌کنند، جایگزین را اعمال می‌کند. این برنامه از یک شنونده پیمایش برای ردیابی موقعیت پیمایش عنصر ریشه استفاده می‌کند و ویژگی transform نوار پیشرفت را براساس آن به‌روز می‌کند.

<script>
  if (!CSS.supports('animation-timeline', 'scroll()')) {
    const progress = document.querySelector('#progress');

    window.addEventListener('scroll', () => {
      const scrollable = document.documentElement.scrollHeight - window.innerHeight;
      const scrolled = window.scrollY;
      const progressPercentage = (scrolled / scrollable);

      progress.style.transform = `scaleX(${progressPercentage})`;
    });
  }
</script>