ساخت نوار بارگذاری در بالای صفحه با 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 ساده برای استفاده در پروژههای بزرگ است.
آیا این مطلب برای شما مفید بود ؟




