ویژگی تصویر

ساخت نوار بارگذاری در بالای صفحه با CSS

  /  CSS   /  ساخت نوار بارگذاری در بالای صفحه با CSS
بنر تبلیغاتی الف

نوار بارگذاری (Loading Bar) که در بالای صفحه قرار می‌گیرد، یک روش ساده و مؤثر برای نمایش وضعیت بارگذاری محتوا یا عملیات پس‌زمینه است. این نوع نوارها کاربرد زیادی در اپلیکیشن‌های وب، SPAها و هنگام فراخوانی‌های AJAX دارند. در این مقاله به روش‌های پیاده‌سازی با CSS خالص، همراه با کمی JavaScript برای کنترل و بهبود تجربه کاربری می‌پردازیم و نکات بهینه‌سازی، دسترس‌پذیری و اجرا روی موبایل را بررسی می‌کنیم.

چرا از نوار بارگذاری بالای صفحه استفاده کنیم؟

  • کمک به فهم کاربر از پیشرفت عملیات بدون اشغال فضای زیاد
  • قابلیت سفارشی‌سازی و انیمیشن‌های جذاب با CSS
  • قابلیت نمایش حالت determinate و indeterminate

نمونه ساده: نوار بارگذاری تعیین‌شده (Determinate)

<!-- HTML -->
<div class="top-loader" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
  <div class="top-loader__bar"></div>
</div>

<!-- CSS -->
.top-loader{
  position:fixed;
  top:0;
  left:0;
  right:0;
  height:4px;
  background:transparent;
  z-index:9999;
  pointer-events:none;
}
.top-loader__bar{
  height:100%;
  width:0%;
  background:linear-gradient(90deg,#29d,#4ae);
  transition: width 300ms ease;
  will-change: width;
  transform-origin:left center;
}

در این مثال یک کانتینر ثابت در بالای صفحه ساخته‌ایم و عنصر داخلی با تغییر width حرکت می‌کند. استفاده از will-change و transform-origin برای بهبود عملکرد و کاهش ری‌پِین کمک می‌کند.

توضیح و استفاده JavaScript برای کنترل

const loader = document.querySelector('.top-loader__bar');
function setProgress(p){
  const value = Math.max(0, Math.min(100, p));
  loader.style.width = value + '%';
  loader.parentElement.setAttribute('aria-valuenow', value);
}

تابع بالا درصد پیشرفت را می‌گیرد و نمای نوار را با تغییر عرض به‌روزرسانی می‌کند و مقدار ARIA را نیز تنظیم می‌کند تا ابزارهای کمکی اطلاعات صحیح داشته باشند.

نمونه Indeterminate (نامشخص) با انیمیشن

<!-- CSS indeterminate -->
.top-loader__bar.indeterminate{
  width:30%;
  animation: slide 1.2s infinite ease-in-out;
}
@keyframes slide{
  0%{ transform:translateX(-100%); }
  50%{ transform:translateX(50%); }
  100%{ transform:translateX(150%); }
}

حالت نامشخص زمانی مناسب است که زمان دقیق بارگذاری را نمی‌دانیم. به‌جای تغییر width دایماً، انیمیشنی روی translateX انجام می‌دهیم که توسط GPU شتاب می‌گیرد و روان‌تر اجرا می‌شود.

روش‌های بهینه برای عملکرد

  • استفاده از transform (translateX) به‌جای تغییر width برای اجرای سریع‌تر و جلوگیری از reflow
  • اعمال will-change تنها در زمان نیاز و حذف آن پس از پایان کار
  • کاهش پیچیدگی سایه‌ها و گرادیانت‌های سنگین
  • استفاده از requestAnimationFrame برای انیمیشن‌های دستی

مثال کامل: ترکیب determinate و indeterminate با کنترل JS

<!-- HTML -->
<div class="top-loader" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
  <div class="top-loader__bar"></div>
</div>

<!-- CSS -->
.top-loader{ position:fixed; top:0; left:0; right:0; height:3px; z-index:9999; pointer-events:none; }
.top-loader__bar{ height:100%; background:#29d; width:0; transition: transform 300ms linear; transform-origin:left; will-change: transform; }

.top-loader__bar.indeterminate{
  width:40%;
  transition:none;
  animation: move 1.1s infinite linear;
}
@keyframes move{ 0%{ transform:translateX(-120%);} 100%{ transform:translateX(220%);} }

<!-- JS -->
const bar = document.querySelector('.top-loader__bar');
const wrapper = bar.parentElement;
function startIndeterminate(){
  bar.classList.add('indeterminate');
  wrapper.setAttribute('aria-valuenow', -1);
}
function setDeterminate(n){
  bar.classList.remove('indeterminate');
  const v = Math.max(0, Math.min(100, n));
  bar.style.transform = `translateX(${v-100}%)`; // efficient via transform
  wrapper.setAttribute('aria-valuenow', v);
}
function finish(){
  setDeterminate(100);
  setTimeout(()=>{ bar.style.transform='translateX(-100%)'; wrapper.setAttribute('aria-valuenow',0); }, 350);
}

در این نمونه از transform برای حرکت نوار استفاده شده تا reflow کاهش یابد. تابع startIndeterminate برای شروع حالت نامشخص و setDeterminate برای قرار دادن درصد استفاده می‌شود. در finish() نوار تا 100% می‌رود و سپس ریست می‌شود.

ادغام با fetch/AJAX و SPAها

در اپلیکیشن‌های واقعی می‌توانید هنگام شروع درخواست شبکه startIndeterminate() را فراخوانی کرده و در هر رویداد progress (اگر در دسترس) setDeterminate را فراخوانی کنید. در فریم‌ورک‌های مثل React یا Vue می‌توانید وضعیت را در استیت قرار دهید و کنترل را از طریق کامپوننت انجام دهید.

دسترسی (Accessibility)

  • استفاده از role="progressbar" و صفت‌های ARIA مانند aria-valuenow, aria-valuemin, aria-valuemax.
  • برای حالت indeterminate مقدار aria-valuenow را -1 یا حذف کنید و از متن معنادار برای خواندن توسط اسکرین‌ریدرها استفاده کنید.
  • اجتناب از چشمک سریع یا انیمیشن‌های بسیار سریع که می‌تواند برای برخی کاربران مشکل‌ساز باشد.

نمونه جدول: خصوصیات CSS و دلیل استفاده

صفتدلیل استفاده
position:fixedثابت نگه داشتن نوار در بالای صفحه حتی با اسکرول
z-index بالانمایش نوار بالاتر از سایر عناصر
transformاجرای روان‌تر با GPU و جلوگیری از reflow
will-changeاعلان به مرورگر برای بهینه‌سازی درگاه رندر

نکات پیشرفته و توصیه‌های کارشناسی

  • برای تجربه کاربری بهتر، اگر عملیات کمتر از 200-300ms طول می‌کشد، از نمایش نوار صرف‌نظر کنید تا از چشم‌زدگی کاربر جلوگیری شود.
  • در صورت نیاز به نمایش چند نوع بارگذاری هم‌زمان (مثلاً فایل آپلود و بارگذاری صفحه) از نشانه‌های رنگی یا آیکون‌های مجزا استفاده کنید تا سردرگمی پیش نیاید.
  • برای کاهش jank، از تغییرات CSS ساده (transform، opacity) استفاده کنید و از heavy reflow جلوگیری کنید.

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

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: