الوحدة 2 · HTML الدلالي أولًا
نماذج سهلة الوصول
20 دقراءة 4 دبيئة تجريب الكود
الدرس في لمحة
ابنِ نموذج دفع لكل حقل فيه label، وخياراته المترابطة مجمّعة، ويستطيع المتصفّح تعبئته تلقائيًا، وأخطاؤه تُعلَن ويمكن إصلاحها دون الحاجة إلى البصر.
- 1لكل حقل label
- 2اجمع الخيارات المترابطة
- 3ساعد الناس والمتصفّحات على التعبئة
- 4أخطاء يستطيع الناس العثور عليها وإصلاحها
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
يخسر Ticketly ربع عملائه في صفحة الدفع، والتحليلات لا تستطيع أن تقول لماذا. جرّب النموذج بقارئ شاشة فيتّضح السبب: الحقول تُعلن “edit text, edit text, edit text”، وأزرار نوع التذكرة تُعلن “Standing, radio button” بلا سؤال، وحين يفشل الدفع يظهر إطار أحمر لا يدركه من لا يرى الشاشة. النماذج هي المكان الذي تتحوّل فيه إمكانية الوصول مباشرة إلى مال.
لكل حقل label
عنصر <label> المرتبط بحقل إدخال يفعل ثلاثة أشياء: يمنح الحقل اسمه المتاح، ويُظهر للمبصرين ما يجب أن يكتبوه حتى بعد أن يبدؤوا الكتابة، ويجعل نص الـ label قابلًا للنقر، فيكبر الهدف.
<label for="full-name">Full name</label>
<input id="full-name" name="fullName" autocomplete="name">
<label>
Email
<input type="email" name="email" autocomplete="email" required>
</label>الطريقتان تعملان: for تشير إلى id، أو حقل الإدخال متداخل داخل الـ label. ويمكنك التأكّد من الربط في الـ console: يجب أن تكون قيمة document.querySelector('#full-name').labels.length هي 1.
اجمع الخيارات المترابطة
لأزرار الـ radio ومربّعات الاختيار طبقتان من المعنى: كل خيار وحده، والسؤال الذي تجيب عنه معًا. يحمل <fieldset> و<legend> السؤال:
<fieldset>
<legend>Ticket type</legend>
<label><input type="radio" name="ticket" value="standing"> Standing</label>
<label><input type="radio" name="ticket" value="seated"> Seated</label>
<label><input type="radio" name="ticket" value="vip"> VIP lounge</label>
</fieldset>حين يدخل التركيز المجموعة، يقرأ NVDA: “Ticket type, grouping, Standing, radio button, not checked, 1 of 3”. استخدم النمط نفسه لكتلة عنوان الفوترة أو لمجموعة مربّعات «أبلغني عبر».
ساعد الناس والمتصفّحات على التعبئة
خاصيتان توفّران كثيرًا من الكتابة، وهذا أهمّ ما يكون لذوي الإعاقات الحركية أو صعوبات الذاكرة.
الـ type الصحيح يُظهر لوحة المفاتيح المناسبة على الهواتف ويوفّر تحقّقًا أساسيًا: type="email"، وtype="tel"، وinputmode="numeric" لرقم البطاقة.
والخاصية autocomplete تعلن الغرض من الحقل، فيستطيع المتصفّح تعبئته من البيانات المحفوظة. يشترطها معيار WCAG 1.3.5 Identify Input Purpose (AA) للحقول التي تخصّ المستخدم. من القيم الشائعة: name، given-name، family-name، email، tel، street-address، postal-code، country، cc-name، cc-number، cc-exp، cc-csc، username، current-password، new-password.
علِّم الحقول المطلوبة بخاصية required، التي تُعلنها قارئات الشاشة، وبنص مرئي مثل “(required)”، لا بنجمة فقط. ولا تسأل مرتين: إن كتب المستخدم بريده في الخطوة 1، فاملأه مسبقًا في الخطوة 3 (3.3.7 Redundant Entry).
أخطاء يستطيع الناس العثور عليها وإصلاحها
هنا تفشل معظم النماذج. للخطأ الجيد أربعة أجزاء، ويوضّح الرسم كيف تترابط:
- قل أيّ حقل خاطئ، بالنص (3.3.1 Error Identification).
- قل كيف يُصلَح (3.3.3 Error Suggestion): “Enter an email address like name@example.com”، لا “Invalid input”.
- اربطه برمجيًا:
aria-invalid="true"على الحقل وaria-describedbyتشير إلى الرسالة. - انقل التركيز إلى أول حقل غير صالح (أو إلى ملخّص أخطاء في الأعلى في النماذج الطويلة) ليصل المستخدم إلى المشكلة مباشرة.
<label for="email">Email</label>
<input id="email" type="email" autocomplete="email" required>
<p id="email-error" class="error" hidden></p>const form = document.querySelector('#checkout');
const email = form.querySelector('#email');
const error = form.querySelector('#email-error');
form.addEventListener('submit', (event) => {
if (email.value.includes('@')) {
email.removeAttribute('aria-invalid');
email.removeAttribute('aria-describedby');
error.hidden = true;
return;
}
event.preventDefault();
error.textContent = 'Enter an email address like name@example.com';
error.hidden = false;
email.setAttribute('aria-invalid', 'true');
email.setAttribute('aria-describedby', 'email-error');
email.focus();
});يستخدم النموذج novalidate في كود Ticketly (<form id="checkout" novalidate>) لتحلّ هذه الرسالة المخصّصة محلّ الفقاعة المدمجة في المتصفّح، التي تختلف من متصفّح لآخر وتختفي بسرعة. هذا اختيار شائع؛ والإبقاء على التحقّق الأصلي مقبول أيضًا إن كانت رسائله ترضيك.
وفي النموذج الطويل الذي فيه عدة أخطاء، أضف ملخّص أخطاء في الأعلى: عنوانًا مثل “There are 2 problems”، تتبعه قائمة روابط، كلٌّ منها يشير إلى الحقل الذي يصفه (<a href="#email">Enter an email address</a>). وانقل التركيز إلى الملخّص بعد إرسال فاشل. يسمع المستخدمون عدد المشكلات، ويأخذهم كل رابط مباشرة إلى حقل.
تحقّق من صحة المدخلات عند الإرسال أو حين يغادر المستخدم الحقل، لا مع كل ضغطة مفتاح. الصراخ بـ «بريد غير صالح» بينما لا يزال الشخص يكتب الحروف الأولى ضجيج للجميع، وسيل من الإعلانات لمستخدمي قارئ الشاشة.
صارت نماذج Ticketly تتكلّم بوضوح. والجزء الأخير من القسم 2 يتناول محتوى ليس نصًا على الإطلاق: الصور والأيقونات وجداول البيانات في صفحة الأسعار.
أهم النقاط
- كل حقل إدخال يحتاج إلى label برمجي؛ والـ placeholder يختفي عند الكتابة وليس اسمًا يمكن الاعتماد عليه.
- اجمع أزرار الاختيار (radio) ومربّعات الاختيار (checkbox) في fieldset يطرح الـ legend فيه السؤال.
- قيم autocomplete مثل name وemail وcc-number تتيح للمتصفّحات تعبئة الحقول وتحقّق معيار 1.3.5 Identify Input Purpose.
- عند الخطأ، اضبط aria-invalid، واربط الرسالة بـ aria-describedby، واشرح كيف يُصلَح الخطأ، وانقل التركيز إلى أول حقل غير صالح.