نمایش پیشرفت باید بگوید چه چیزی انجام شده و چه چیزی باقی مانده است، تا جایی که سیستم واقعاً این اطلاعات را دارد. نوار متحرکی که فقط گذشت زمان را نشان میدهد، درصد انجام کار نیست. در فرم چندمرحلهای نیز شماره مرحله به معنی زمان باقیمانده نیست. طراحی Progress Indicator از تعریف واحد پیشرفت شروع میشود و شکل خطی یا دایرهای بعد از آن انتخاب میشود.
اگر مقدار کل معلوم نیست، وضعیت نامعین را صادقانه نمایش دهید. عبارت «در حال آمادهسازی» میتواند مناسب باشد، به شرط آنکه همین عملیات در جریان باشد. وعده چند ثانیه یا افزایش دوبرابری صبر کاربر بدون داده مشخص مبنای معتبری ندارد. بازخورد خوب عدم قطعیت را پنهان نمیکند؛ اطلاعات قابل اعتماد و راه ادامه را ارائه میدهد.
مقدار کار را از مدت انتظار جدا کنید
در نمونه فرضی پردازش چند سند، تعداد سندهای انجامشده ممکن است معلوم باشد ولی زمان هر سند متفاوت باشد. «سه مورد از ده مورد» اطلاعات معتبر درباره شمار کارها میدهد، اما لزوماً ۳۰ درصد زمان تمام نشده است. این نمونه نتیجه یک مشتری واقعی نیست. نام شاخص باید واحد سنجش را روشن کند تا کاربر از یک عدد برداشت زمانی نادرست نداشته باشد.
در upload، byteهای ارسالشده واحد انتقالاند. پس از ارسال، بررسی فایل میتواند ادامه داشته باشد. نوار انتقال باید به مرحله بعد تبدیل شود و موفقیت نهایی فقط پس از نتیجه معتبر اعلام شود. اگر تمام مراحل در یک درصد ترکیب میشوند، وزن و روش محاسبه باید تعریف شده باشد. افزایش تزئینی تا ۹۹ درصد، این تعریف را نمیسازد.
زمان تخمینی را فقط با مبنای مناسب نمایش دهید. سرعت لحظهای و مقدار باقیمانده ممکن است تخمینی ایجاد کنند، اما نوسان شبکه آن را تغییر میدهد. از واژه تقریبی و بهروزرسانی متناسب استفاده کنید. اگر تخمین قابل اعتماد ندارید، نام مرحله و وضعیت بهتر از شمارش معکوس ساختگی است. اطلاعات نادرست میتواند انتظار و تصمیم خروج را گمراه کند.
Determinate و Indeterminate معنای متفاوت دارند
راهنمای progress در MDN مقدار value را نسبت کار انجامشده به max تعریف میکند. حذف value حالت indeterminate میسازد. مقدار صفر با نبود مقدار فرق دارد: صفر یعنی ابتدای کار معلوم و نبود value یعنی پیشرفت اندازهگیریشده اعلام نشده است. این تفاوت باید در state و نمایش حفظ شود.
تغییر از نامعین به معلوم زمانی منطقی است که کل و مقدار جاری در دسترس قرار گرفتهاند. برای مثال، دریافت فهرست کارها میتواند مرحله اولیه نامعین باشد و اجرای آنها مرحله معلوم. تغییر شکل ناگهانی بدون توضیح ممکن است شبیه شروع دوباره باشد. نام مرحله را کنار نوار نگه دارید تا علت تغییر برای کاربر مشخص شود.
درصد را با منبع معتبر هماهنگ کنید. اگر total صفر است یا هنوز معلوم نیست، تقسیم عدد انجامشده بر آن نتیجه معتبر تولید نمیکند. مقدار خارج از محدوده باید در قرارداد داده بررسی شود. پنهان کردن خطای داده با یک عدد تصادفی یا clamp بیتوضیح، گزارش واقعی نمیسازد؛ تیم باید علت ناسازگاری را پیگیری کند.
Stepper مسیر مراحل را معرفی میکند
در فرم چندمرحلهای، Stepper میتواند جای فعلی و مراحل بعدی را نشان دهد. نام مرحلهها باید کاری را که انجام میشود بیان کند، مانند «نشانی» و «مرور سفارش». شماره تنها برای فهم محتوا کافی نیست. مرحله اختیاری یا شرطی را با مسیر واقعی هماهنگ کنید؛ فهرست ثابت برای همه کاربران ممکن است مرحلهای را نشان دهد که آنها هرگز نمیبینند.
مرحله جاری با مرحله انتخابشده یا کاملشده یکسان نیست. aria-current میتواند current step را معرفی کند. آن را روی همه مرحلهها true نگذارید. کامل شدن نیاز به نشانه و متن جدا دارد و نباید فقط از رنگ سبز استنباط شود. وضعیت باید در متن و ساختار نیز قابل تشخیص باشد.
اگر مرحله قبلی قابل انتخاب است، آن را با link یا button مناسب ارائه کنید. مراحل آینده لزوماً باید قابل کلیک باشند؟ پاسخ به اعتبارسنجی و وابستگیها مربوط است. کاربر نباید با انتخاب یک مرحله، دادهای را بدون اطلاع از دست بدهد. مسیر بازگشت و حفظ ورودی را همراه Stepper طراحی کنید؛ نمایش مسیر بدون رفتار کامل، صرفاً نقشه ظاهری است.
نمونه مستقل مرحلهها بدون درصد زمانی
در فایل زیر، کاربر بین سه مرحله آموزشی حرکت میکند. نوار درصد زمان نداریم، چون زمان انجام کار هر فرد معلوم نیست. شماره و نام مرحله جاری معرفی میشوند و لینکهای مرحلههای قبلی در این مثال وجود ندارند؛ دکمه قبل مسیر بازگشت را فراهم میکند. فایل را با نام index.html ذخیره و باز کنید. dependency، شبکه و دارایی تصویری ندارد.
<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>نمونه Stepper</title>
<style>
body { margin:0; color:#17212b; background:#f4f6f9; font:1rem/1.9 system-ui,sans-serif; }
main { max-inline-size:42rem; margin-inline:auto; padding:2rem 1rem; }
ol { display:flex; flex-wrap:wrap; gap:1.5rem; padding-inline-start:1.5rem; }
[aria-current="step"] { font-weight:700; text-decoration:underline; text-underline-offset:.3rem; }
section { background:#fff; border:1px solid #64748b; border-radius:.5rem; padding:1rem; }
button { font:inherit; color:#fff; background:#164ca4; border:0; padding:.4rem .8rem; margin-block:1rem; }
button:disabled { opacity:.6; }
:focus-visible { outline:3px solid #164ca4; outline-offset:3px; }
</style>
</head>
<body>
<main>
<h1>مسیر آموزشی سهمرحلهای</h1>
<p>این نمونه دادهای دریافت یا ثبت نمیکند.</p>
<ol aria-label="مراحل نمونه"><li aria-current="step">معرفی</li><li>مرور</li><li>پایان</li></ol>
<p id="position">مرحله ۱ از ۳</p>
<section><h2 id="step-title" tabindex="-1">معرفی</h2><p id="step-text">در این مرحله، هدف مسیر معرفی میشود.</p></section>
<button id="previous" type="button" disabled>مرحله قبل</button>
<button id="next" type="button" disabled>مرحله بعد</button>
<p id="status" role="status"></p>
<noscript><p>برای جابهجایی مراحل این نمونه، JavaScript لازم است.</p></noscript>
</main>
<script>
const steps = [
{ title:'معرفی', text:'در این مرحله، هدف مسیر معرفی میشود.' },
{ title:'مرور', text:'در این مرحله، اطلاعات نمونه مرور میشوند؛ هیچ فرم واقعی وجود ندارد.' },
{ title:'پایان', text:'با انتخاب پایان نمونه، فقط پیام محلی نشان داده میشود.' }
];
const items = [...document.querySelectorAll('ol li')];
const previous = document.getElementById('previous');
const next = document.getElementById('next');
const title = document.getElementById('step-title');
let current = 0;
function render(moveFocus) {
items.forEach((item,index) => {
if (index === current) item.setAttribute('aria-current','step');
else item.removeAttribute('aria-current');
});
title.textContent = steps[current].title;
document.getElementById('step-text').textContent = steps[current].text;
document.getElementById('position').textContent = `مرحله ${current + 1} از ${steps.length}`;
document.getElementById('status').textContent = '';
previous.disabled = current === 0;
next.disabled = false;
next.textContent = current === steps.length - 1 ? 'پایان نمونه' : 'مرحله بعد';
if (moveFocus) title.focus();
}
previous.addEventListener('click', () => { if (current > 0) { current--; render(true); } });
next.addEventListener('click', () => {
if (current < steps.length - 1) { current++; render(true); }
else document.getElementById('status').textContent = 'نمونه تمام شد؛ دادهای ثبت نشده است.';
});
render(false);
</script>
</body>
</html>
این مثال فرم واقعی و ثبت سروری ندارد؛ محتوای هر مرحله توضیح آموزشی است. دکمه پایان پیام روشن درباره همین محدوده میدهد. در محصول واقعی، گذار مرحله باید بعد از اعتبارسنجی معتبر باشد و ذخیرهسازی مطابق قرارداد انجام شود. نگه داشتن شماره مرحله در JavaScript به تنهایی به معنی ذخیره داده یا تکمیل سفارش نیست.
پس از تغییر مرحله، عنوان بخش Focus میگیرد تا کاربر Keyboard از زمینه جدید باخبر شود. ناحیه مرحلهها همچنان ترتیب متنی دارد و current step جدا علامتگذاری میشود. دکمه پایان با دکمه ادامه نام متفاوتی دارد. این تصمیمها برای جلوگیری از برداشت ارسال نهایی در مرحله میانی انتخاب شدهاند؛ ظاهر Stepper تنها بخش رفتار نیست.
پیشرفت async به توقف و شکست هم نیاز دارد
اگر کار متوقف یا ناموفق شد، وضعیت پیشرفت نباید همچنان حرکت کند. علت معلوم و روش ادامه را معرفی کنید. در عملیات بخشی، شمار اقلام موفق و ناموفق را جدا بیان کنید. رسیدن تعداد بررسیشده به کل، به معنی موفقیت همه نیست. پیام پایان باید نتیجه را توضیح دهد و امکان پیگیری موارد باقیمانده را فراهم کند.
Pause با Cancel فرق دارد. Pause انتظار ادامه همان کار را میسازد و Cancel پایان آن مسیر را القا میکند. اگر سیستم نمیتواند ادامه از همان نقطه را تضمین کند، دکمه توقف را با نام Pause معرفی نکنید. برای کار دارای اثر سروری، قطع دریافت کلاینت لزوماً عمل سرور را متوقف نمیکند؛ وضعیت باید از قرارداد واقعی عملیات بیاید.
در Refresh یا بازگشت به صفحه، پیشرفت محلی ممکن است از بین برود. اگر کار همچنان روی سرور اجرا میشود، شناسه و مسیر بازیابی وضعیت لازم است. شروع دوباره بدون بررسی میتواند عملیات تکراری ایجاد کند. مقاله Loading States نمونه لغو و تفکیک error و empty را برای عملیات آموزشی محدود بررسی میکند.
اطلاعات را بدون اعلان مزاحم ارائه کنید
نوار پیشرفت باید نام قابل دسترس و مقدار درست داشته باشد. برای تغییرهای سریع، اعلان تمام درصدها میتواند خواندن را مختل کند. پیام وضعیت را برای رخدادهای معنادار مانند شروع مرحله، توقف و پایان استفاده کنید. معیار Status Messages درباره ارائه پیام بدون گرفتن Focus توضیح میدهد. تغییر مرحله فرم، با تغییر زمینه، قرارداد دیگری دارد.
حرکت دائمی تنها نشانه انجام کار نباشد. متن و وضعیت باید در حالت کاهش حرکت باقی بمانند. رنگ خط یا دایره نیز باید همراه نام و مقدار معنا بدهد. در Dark Mode، بخش انجامشده و زمینه باید قابل تشخیص باشند. مقاله طراحی Dark Mode به نقشهای رنگی و ترکیب واقعی آنها میپردازد.
در عرض کوچک، نام مرحلهها را تا حد ابهام کوتاه نکنید. میتوانید مرحله جاری و شمار کل را برجسته و مسیر کامل را در ساختار مناسب نگه دارید. ترتیب خواندن RTL و نام انگلیسی داخل آن باید درست بماند. اگر Stepper افقی scroll میشود، کاربر باید به مرحله جاری برسد بدون اینکه کنترلهای فرم از دید خارج شوند.
در تحویل، منبع هر عدد را ثبت کنید
برای Progress معلوم، واحد، total و completed را بنویسید و برای تخمین زمان، مبنا و محدوده را مشخص کنید. برای Stepper، مرحلههای شرطی و روش بازگشت را ثبت کنید. اگر اطلاعاتی در دسترس نیست، state نامعین باید صریح تعریف شود. این قرارداد جلوی افزودن درصد تزئینی توسط بخش دیگری از تیم را میگیرد.
از کاربر بخواهید توضیح دهد چه چیزی انجام شده و چه چیزی باقی مانده است. برداشت او را با واقعیت سیستم مقایسه کنید. UX Writing برای نام مرحله و CTA برای کنترل ادامه و پایان کمک میکنند. پیشرفت قابل اعتماد باید پس از خطا، بازگشت و تغییر مسیر نیز معنای درست خود را حفظ کند.
هنوز دیدگاهی ثبت نشده
اولین نفری باشید که نظر میدهد!