فرم خوب به کاربر کمک میکند اطلاعات لازم را با خطای کمتر وارد کند و وضعیت عملیات را بفهمد. متن قبلی این صفحه عددهای ثابت درباره افزایش پنجاهدرصدی conversion و رشد هفتدرصدی ترک به ازای هر فیلد داشت، بدون منبع یا زمینه. این اعداد حذف شدهاند. یک فیلد اضافه ممکن است بیدلیل باشد یا برای انجام درست خدمت ضروری باشد. تصمیم باید از نیاز محصول و مسیر کاربر بیاید. در این راهنما ساختار، label، اعتبارسنجی، خطا و ارسال را با یک نمونه کامل محلی بررسی میکنیم.
برای هر فیلد دلیل بنویسید
پیش از طراحی، مشخص کنید هر داده برای چه کاری لازم است و چه کسی از آن استفاده میکند. اگر تیم هنوز کاربرد شماره تماس را نمیداند، شاید درخواست آن زود باشد. اگر خدمت به آدرس ارسال وابسته است، حذف آدرس به معنی فرم بهتر نیست. زمان دریافت داده هم اهمیت دارد؛ بعضی اطلاعات را میتوان پس از انتخاب خدمت گرفت. این تقسیم باید با فرایند پشت فرم هماهنگ باشد تا کاربر بعداً مجبور نشود همان داده را دوباره وارد کند.
فیلد اختیاری را روشن معرفی کنید. ستاره بدون توضیح ممکن است برای بعضی کاربران مبهم باشد. اگر بیشتر فیلدها لازماند، قرارداد نمایش را در ابتدای فرم کوتاه بنویسید و موارد اختیاری را نام ببرید. درخواست داده حساس باید دلیل داشته باشد و روش نگهداری آن مشخص باشد. فرم فقط یک رابط نیست؛ نقطه جمعآوری داده است. حذف داده غیرضروری هم تجربه را سادهتر میکند و هم حجم اطلاعاتی را که تیم باید مدیریت کند کمتر میکند.
Label باید پس از تایپ هم باقی بماند
راهنمای W3C برای Label روش ارتباط نام کنترل با فیلد را توضیح میدهد. Placeholder جای label را نمیگیرد، چون هنگام ورود داده ممکن است ناپدید شود و معمولاً برای راهنمای کامل کافی نیست. نام فیلد باید روشن و متناسب با واژههای مخاطب باشد. «شناسه» بدون توضیح در محصولی که چند شناسه دارد مبهم است. اگر قالب خاصی میخواهید، نمونه یا راهنمای کوتاه را نزدیک همان فیلد قرار دهید.
برای گروه گزینهها، fieldset و legend میتوانند رابطه را روشن کنند. چند radio بدون عنوان مشترک ممکن است سؤال اصلی را به کاربر نرسانند. نام قابل دسترس و متن دیداری باید درباره همان مفهوم صحبت کنند. اگر کنترل icon-only است، متن لازم را از روش مناسب بدهید. ابزار native پایه رفتار صفحهکلید و فرم را فراهم میکند؛ جایگزینکردن آن با عنصر غیرتعاملی نیاز به پیادهسازی بیشتری دارد. ظاهر خاص دلیلی برای حذف این قراردادها نیست.
اعتبارسنجی باید به اصلاح کمک کند
راهنمای اعتبارسنجی W3C بر اطلاعات راهنما و کمک به جلوگیری از خطا تأکید دارد. اگر ورودی هنوز در حال تایپ است، نمایش مداوم خطا میتواند مزاحم باشد. زمان بررسی را با نوع فیلد هماهنگ کنید؛ بعضی بررسیها پس از خروج از فیلد مناسباند و برخی هنگام ارسال. متن خطا باید بگوید چه چیزی نیاز به اصلاح دارد. فقط تغییر رنگ یا عبارت «اشتباه است» کار بعدی را روشن نمیکند.
اعتبارسنجی سمت client برای بازخورد سریع مفید است، اما سرور باید مستقل داده را بررسی کند. درخواست میتواند بدون رابط شما ساخته شود. طول، نوع و قواعد کسبوکار را در قرارداد سرور تعریف کنید. اگر server یک ورودی را رد میکند، پاسخ باید به فیلد و دلیل مربوط وصل شود. اختلاف قواعد client و server کاربر را سردرگم میکند؛ او دادهای را درست میبیند و بعد پاسخ دیگری میگیرد. مرجع قواعد و روش تغییر آنها را در تیم روشن نگه دارید.
نمونه کامل فرم محلی
فایل زیر را با نام request-form.html ذخیره کنید و در مرورگر باز کنید. به کتابخانه یا سرور نیاز ندارد. نمونه یک فرم درخواست با نام و ایمیل میسازد و فقط در همان صفحه اعتبارسنجی انجام میدهد؛ اطلاعات ارسال یا ذخیره نمیشوند. پیام پایانی همین محدودیت را توضیح میدهد تا موفقیت نمایشی با ثبت واقعی اشتباه نشود. برای استفاده در محصول، باید endpoint واقعی، قرارداد خطا و وضعیت ارسال را جدا اضافه کنید. selectorها و شناسههای JavaScript در همین HTML موجودند.
<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>نمونه فرم درخواست</title>
<style>
* { box-sizing: border-box; }
body { font-family: sans-serif; line-height: 1.8; padding: 1rem; color: #172333; }
main { max-width: 32rem; margin-inline: auto; }
.field { margin-block: 1rem; }
label { display: block; font-weight: bold; }
input { width: 100%; padding: .7rem; border: 1px solid #65788d; border-radius: .3rem; font: inherit; }
input[aria-invalid="true"] { border: 2px solid #a11a24; }
.error { color: #a11a24; margin: .3rem 0; }
button { font: inherit; padding: .6rem 1rem; background: #174b8c; color: white; border: 0; border-radius: .3rem; }
:focus-visible { outline: 3px solid #914200; outline-offset: 3px; }
</style>
</head>
<body>
<main>
<h1>فرم درخواست نمونه</h1>
<p>هر دو فیلد لازماند. این نمونه داده را ارسال یا ذخیره نمیکند.</p>
<form id="request-form" novalidate>
<div class="field">
<label for="full-name">نام</label>
<input id="full-name" name="fullName" required maxlength="100" autocomplete="name" aria-describedby="name-error">
<p class="error" id="name-error"></p>
</div>
<div class="field">
<label for="email">ایمیل</label>
<input id="email" name="email" type="email" required autocomplete="email" dir="ltr" aria-describedby="email-help email-error">
<p id="email-help">آدرس را با قالب name@example.com وارد کنید.</p>
<p class="error" id="email-error"></p>
</div>
<button type="submit">بررسی فرم</button>
</form>
<p id="status" role="status"></p>
</main>
<script>
const form = document.querySelector('#request-form');
const nameInput = document.querySelector('#full-name');
const emailInput = document.querySelector('#email');
const status = document.querySelector('#status');
form.addEventListener('submit', (event) => {
event.preventDefault();
const fields = [
{ input: nameInput, error: document.querySelector('#name-error'), valid: nameInput.value.trim().length > 0 && nameInput.checkValidity(), message: 'نام را وارد کنید؛ حداکثر ۱۰۰ نویسه.' },
{ input: emailInput, error: document.querySelector('#email-error'), valid: emailInput.checkValidity(), message: 'یک آدرس ایمیل با قالب معتبر وارد کنید.' }
];
let firstInvalid = null;
for (const field of fields) {
field.input.setAttribute('aria-invalid', String(!field.valid));
field.error.textContent = field.valid ? '' : field.message;
if (!field.valid && !firstInvalid) firstInvalid = field.input;
}
if (firstInvalid) {
status.textContent = 'فیلدهای مشخصشده را اصلاح کنید.';
firstInvalid.focus();
} else {
status.textContent = 'ورودیها معتبرند. این نمونه محلی است و اطلاعاتی ارسال نشد.';
}
});
</script>
</body>
</html>
در این مثال labelها با for به id فیلدها وصلاند و راهنما و خطا با aria-describedby معرفی شدهاند. هنگام خطا، aria-invalid فعال میشود و focus به نخستین فیلد نامعتبر میرود. پیام کلی هم با role=status تغییر وضعیت را اعلام میکند. form ویژگی novalidate دارد تا بازخورد نمونه یک مسیر مشخص داشته باشد؛ required و type همچنان برای checkValidity استفاده میشوند. این انتخاب آموزشی است و میتوان در پروژه ساده رفتار اعتبارسنجی native مرورگر را هم به کار گرفت.
نام پس از trim بررسی میشود تا ورودی فقط فاصله پذیرفته نشود. ایمیل در نمونه با قرارداد type=email بررسی میشود، اما این بررسی وجود صندوق یا مالکیت آدرس را ثابت نمیکند. اگر محصول نیاز به تأیید مالکیت دارد، فرایند جدا لازم است. داده ورودی با textContent نمایش داده میشود و داخل HTML خام قرار نمیگیرد. همین جزئیات کوچک باید با توضیح مقاله سازگار باشند تا خواننده از وجود یک پیام موفقیت، قابلیت ارسال و ذخیره را نتیجه نگیرد.
ارسال، انتظار و خطای شبکه
در فرم واقعی، حالت در حال ارسال را نشان دهید و از درخواست تکراری ناخواسته جلوگیری کنید. تغییر متن دکمه و پیام وضعیت میتواند مفید باشد، اما کاربر باید بداند چه اتفاقی میافتد. اگر شبکه قطع شد، فیلدهای سالم را حفظ کنید و امکان تلاش دوباره بدهید. خطای شبکه با خطای ورودی فرق دارد؛ نباید شماره یا ایمیل کاربر را نامعتبر معرفی کنید وقتی مشکل از ارتباط است. این تفکیک به اعتماد و کاهش اصلاح بیهوده کمک میکند.
اگر نتیجه عملیات حساس است، سرور باید تکرار درخواست را مدیریت کند. غیرفعالکردن دکمه در client به تنهایی جلوی تکرار از تب دیگر یا ارسال دوباره پس از وقفه را نمیگیرد. قرارداد Idempotency و شناسه عملیات باید با backend طراحی شود. مقاله الگوهای طراحی API درباره مرز درخواست و پاسخ ادامه مناسبی دارد. UX خوب به رفتار سیستم متکی است؛ یک ظاهر آرام نمیتواند ثبت دوباره سفارش را جبران کند.
پیام موفقیت باید اقدام بعدی را روشن کند. اگر پاسخ تیم زمان مشخصی دارد، همان زمان تأییدشده را بنویسید. اگر فقط دریافت درخواست ثبت شده، آن را با تأیید نهایی خدمت برابر نگیرید. شماره پیگیری و راه مراجعه بعدی میتواند مفید باشد، به شرطی که واقعاً در سیستم وجود داشته باشد. از ساختن یک شماره تصادفی فقط برای نمایش اطمینان پرهیز کنید. کاربر باید بتواند پیام را به عملیات واقعی وصل کند و بعداً از آن استفاده کند.
فرم فارسی و ورودی ترکیبی
صفحه RTL است، اما بعضی ورودیها مانند ایمیل و URL بهتر است جهت LTR داشته باشند. جهت، زبان و نوع داده را جدا تعیین کنید. برای شماره، ارقام فارسی و عربی ممکن است وارد شوند؛ اگر معادلاند، normalization مناسب میتواند اصطکاک را کم کند. قرارداد پذیرش را روشن کنید و خطای ناگهانی برای یک تفاوت نگارشی نسازید. قالب تاریخ هم باید مشخص باشد. کاربر نباید از ترتیب روز و ماه حدس بزند سیستم کدام تقویم را میخواهد.
در موبایل، type و autocomplete مناسب میتوانند ورود را آسانتر کنند. با این حال، autocomplete باید به معنی فیلد مربوط باشد و اطلاعات اشتباه وارد نکند. اندازه کنترل و فاصله آنها را برای لمس در نظر بگیرید. متن خطا ممکن است چند خط شود؛ ارتفاع ثابت نباید آن را پنهان کند. برای layout، ترتیب DOM را حفظ کنید تا صفحهکلید و فناوری کمکی مسیر منطقی داشته باشند. مقاله دسترسیپذیری سایت فارسی درباره همین مسیرها بیشتر توضیح میدهد.
Multi-step و Auto-save همیشه لازم نیستند
فرم چندمرحلهای برای گروههای واقعی اطلاعات مفید است، اما تقسیم یک فرم کوتاه به چند صفحه میتواند انتظار و جابهجایی اضافه بسازد. اگر این الگو را انتخاب میکنید، عنوان مرحله، پیشرفت و امکان بازگشت را روشن کنید. داده مرحله قبلی نباید بیدلیل پاک شود. مقاله طراحی Multi-step Wizard ادامه این بحث است. تصمیم درباره تعداد مرحله باید به ساختار اطلاعات و مسیر کاربر وصل باشد و صرفاً از ظاهر مدرن الگو نیاید.
Auto-save نیز درباره محل و عمر داده تصمیم میخواهد. پیشنویس حساس روی دستگاه مشترک ممکن است مسئله ایجاد کند. اگر اطلاعات را موقت نگه میدارید، وضعیت ذخیره و روش پاککردن را توضیح دهید. ذخیره محلی با ذخیره در حساب کاربر برابر نیست. اگر کاربر دستگاه را عوض کند، باید بداند پیشنویس همراه او میآید یا نه. این قرارداد از نظر تجربه به اندازه نحوه نمایش دکمه مهم است و باید پیش از پیادهسازی روشن شود.
کیفیت را با مسیر واقعی بسنجید
تعداد فیلدها تنها معیار نیست. ببینید کاربر سؤال را میفهمد، داده لازم را دارد و پس از خطا میتواند ادامه دهد یا نه. در گزارش، شروع فرم، ارسال معتبر و نتیجه واقعی را جدا تعریف کنید. اگر رخداد یکسان چند بار ثبت میشود، عدد را به تعداد افراد تبدیل نکنید. بدون داده و روش مقایسه، درصد افزایش conversion نسازید. یافته کیفی مشخص مثل «کاربر منظور فیلد شناسه را نمیفهمد» میتواند یک اصلاح روشن ایجاد کند.
برای شروع، یک فرم مهم را انتخاب کنید و کاربرد هر فیلد، label، خطا و پیام پایانی را کنار هم بنویسید. سپس حالت انتظار و قطع ارتباط را به همان قرارداد اضافه کنید. موارد تکراری را در component مشترک ثبت کنید تا صفحه بعدی دوباره همان مسئله را نسازد. فرم مناسب از این تصمیمهای مرتبط شکل میگیرد: داده لازم، راهنمای قابل فهم و نتیجهای که با عملیات واقعی سیستم هماهنگ است. کوتاهبودن ظاهر به تنهایی جای این کیفیت را نمیگیرد.
هنوز دیدگاهی ثبت نشده
اولین نفری باشید که نظر میدهد!