HTML الدلالية لإمكانية الوصول
HTML الدلالية (Semantic HTML) تعني اختيار العنصر الذي يعبّر عن طبيعة المحتوى: <h2> لعنوان قسم، و<nav> لقائمة الموقع، و<ul> لقائمة خيارات، و<button> لإجراء، و<label> لاسم حقل، و<th> لرأس جدول. ومن هذه العناصر يبني المتصفح شجرة إمكانية الوصول (Accessibility tree) المكوّنة من أدوار وأسماء وحالات، وهذه الشجرة، لا البكسلات على الشاشة، هي ما ينطقه قارئ الشاشة وما يستمع إليه التحكم الصوتي. والعناصر الأصلية (Native elements) نفسها هي التي تحدد ما يستطيع مفتاح Tab الوصول إليه.
قدّم درس «أساسيات HTML للمختبِرين» العناصرَ نفسها. وينظر هذا الدرس إليها من الجهة الأخرى: ما الذي يمنحه كل عنصر للتقنيات المساعدة (Assistive Technology)، وما الذي يضيع حين تُبنى الصفحة من <div> و<span> فقط، وكيف تفحص الفرق في صفحة حقيقية قبل أي جلسة اختبار بلوحة المفاتيح أو بقارئ الشاشة.
لماذا يهم
قد تبدو الصفحة المبنية من عناصر <div> منسّقة مكتملةً وهي مع ذلك غير قابلة للاستخدام: يسمع مستخدم قارئ الشاشة «قابل للنقر» بدلاً من «زر»، ويفتح قائمة عناوين فارغة، ويقع في حقل بلا اسم، ويقرأ رقماً في جدول بلا عمود. وكل واحدة من هذه إخفاق في معيار النجاح 1.3.1 المعلومات والعلاقات (Info and Relationships) أو 4.1.2 الاسم والدور والقيمة (Name, Role, Value) من WCAG 2.2، وكلاهما من المستوى A، فتفشل الصفحة في المطابقة عند أدنى مستوى، ولا يستطيع من يعتمدون على التقنيات المساعدة إتمام المهمة.
وبالنسبة إلى المختبِر، الدلالات من أرخص فحوص إمكانية الوصول. فلا تحتاج إلى قارئ شاشة لترى أن العنوان مجرد <div> منسّق أو أن حقل الإدخال بلا <label>: تُظهر الشيفرة ولوحة إمكانية الوصول في المتصفح ذلك في ثوانٍ، والإصلاح غالباً تغيير عنصر واحد. واكتشاف ذلك في أول مراجعة لمكوّن جديد يوفّر جولة كاملة من اختبار قارئ الشاشة لاحقاً، كما أن الأدوار والأسماء نفسها تجعل الاختبارات الآلية والمحددات (Locators) أكثر استقراراً.
من الشيفرة إلى شجرة إمكانية الوصول
حين يحلّل المتصفح HTML يبني نموذج DOM، أي الشجرة الحية لعناصر الصفحة، ومنه يبني بنية ثانية: شجرة إمكانية الوصول. يصبح كل عنصر ذي معنى عقدة لها دور (Role) مثل عنوان أو رابط أو زر أو مربع نص أو خلية، واسم قابل للوصول (Accessible name) مثل نص العنوان أو نص الرابط أو تسمية الحقل، وحالات أو خصائص مثل عنوان من المستوى 2 أو مطلوب أو محدد أو معطّل. أما العناصر التي لا تحمل معنى، مثل <div> و<span>، فتصبح عقداً عامة (Generic) أو تُحذف من الشجرة كلياً.
تقرأ قارئات الشاشة والتحكم الصوتي هذه الشجرة عبر واجهة برمجة إمكانية الوصول (Accessibility API) في نظام التشغيل، لا البكسلات المعروضة. فيعلن قارئ الشاشة الدور والاسم معاً («Place order، زر»)، ويعرض قوائم بالعناوين والمعالم والروابط ليقفز المستخدم بدلاً من القراءة بالترتيب، ويستخدم الدور ليحدد المفاتيح التي تشغّل العنصر. ويفعّل التحكم الصوتي ما يسمّيه المستخدم («انقر Place order»)، لذا يجب أن يوجد الاسم المنطوق في الشجرة. ولا يصل مستخدمو لوحة المفاتيح إلا إلى ما هو قابل للتركيز (Focusable)، وعناصر التحكم الأصلية كذلك افتراضياً. ولا يستطيع التنسيق أن يضيف دوراً: فقد يُخفي CSS محتوى من الشجرة، لكن عنصر <div> المنسّق ليبدو زراً يظل عقدة عامة فيها.
- الدور: أي نوع من الأشياء هو. يأتي من العنصر (
<button>و<h2>و<a href>)، أو في الملاذ الأخير من سمة دور ARIA، وهو ما يتناوله درس لاحق. - الاسم: ماذا يُسمّى. يحسبه المتصفح من المحتوى أو من
<label>أوaltأو<caption>أو سمات ARIA، بترتيب ثابت تحدده مواصفة حساب الاسم القابل للوصول. - الحالة والقيمة: ماذا يفعل الآن. تُبقيها العناصر الأصلية محدّثة دون أي جهد:
<input type="checkbox">محدد، و<button>معطّل، والنص المكتوب في<textarea>.
العناوين والمعالم والقوائم: البنية التي يتنقل بها المستخدمون
نادراً ما يقرأ مستخدمو قارئات الشاشة الصفحة من أعلاها إلى أسفلها. فهم يفتحون قائمة العناوين ليعرفوا ما تحتويه الصفحة، ويقفزون إلى معلم main لتخطي قائمة التنقل، ويسمعون «قائمة، أربعة عناصر» قبل أي قائمة ليعرفوا حجم ما هو قادم. وكل حركة من هذه تعتمد على استخدام عنصر واحد بعينه، ولكل منها فحص دقيق.
- العناوين من
<h1>إلى<h6>: عنوان<h1>واحد لموضوع الصفحة، و<h2>لأقسامها، و<h3>داخلها. والعنوان المرئي المصنوع من نص عريض داخل<div>غائب عن قائمة العناوين ويخفق في 1.3.1؛ ونص العنوان الذي لا يصف قسمه يخفق في 2.4.6 العناوين والتسميات (Headings and Labels) من المستوى AA. أما تخطي المستويات فيربك المستخدمين لكنه ليس إخفاقاً في WCAG بحد ذاته، فأبلغ عنه بخطورة أقل. - المعالم (Landmarks): في المستوى الأعلى من الصفحة يقابل
<header>دور banner، و<nav>دور navigation، و<main>دور main، و<aside>دور complementary، و<footer>دور contentinfo. ولا يصبح<section>منطقة (Region) إلا إذا كان له اسم، يأتي عادةً من السمةaria-labelledbyالتي تشير إلى عنوانه أو من السمةaria-label. وتتيح المعالم للمستخدمين تخطي الكتل المتكررة في كل صفحة، وهو ما يطلبه المعيار 2.4.1 تخطي الكتل (Bypass Blocks). تحقق من أن المحتوى داخل<main>، وأن عنصري<nav>يحملان اسمين مختلفين مثل «القائمة الرئيسية» و«روابط التذييل». - القوائم
<ul>و<ol>: يعلن قارئ الشاشة بداية القائمة وعدد عناصرها. وقائمة التنقل المبنية من صفوف<div>تُقرأ أسطراً غير مترابطة، وقائمة<ol>لخطوات الدفع تفقد ترتيبها حين تتحول إلى div. والنقاط المنسّقة وحدها لا تصنع قائمة.
الأزرار والروابط والتسميات والجداول: الاسم والدور والعلاقات
المجموعة الثانية هي مجال المعيار 4.1.2 الاسم والدور والقيمة: يجب أن يكشف كل مكوّن في واجهة المستخدم اسمه ودوره وحالاته وقيمته للتقنيات المساعدة. وتفعل العناصر الأصلية ذلك افتراضياً؛ أما البدائل المبنية من <div> أو <span> فلا، والعنصر الأصلي الخاطئ عيب أيضاً.
- زر أم رابط:
<button>ينفّذ إجراءً في هذه الصفحة (إرسال، فتح، حذف) ويُفعَّل بمفتاحي Enter وSpace؛ و<a href>ينقلك إلى مكان آخر ويُفعَّل بمفتاح Enter وحده. يعلن قارئ الشاشة كلاً منهما بطريقة مختلفة ويضع الروابط في قائمة مستقلة، لذا فإن<div onclick>الذي يعمل زراً، أو الرابط المنسّق كزر الذي لا يشغّل إلا نصاً برمجياً، له نتيجة متوقعة واضحة: العنصر الأصلي المناسب لما يفعله. و<a>بلاhrefليس رابطاً أصلاً: فهو غير قابل للتركيز، ويُقرأ نصه نصاً عادياً لا رابطاً. - التسميات: يأتي اسم الحقل من
<label>تساوي سمتهforمعرّف الحقلid، أو من<label>يحيط بالحقل. ونص العنصر النائب (Placeholder) مجرد بديل احتياطي في حساب الاسم ويختفي بمجرد أن يبدأ المستخدم الكتابة، لذا فالحقل الذي تسميته الوحيدة نص نائب عيب يجب الإبلاغ عنه. وتأخذ مجموعة أزرار الاختيار أو مربعات التحديد سؤالها المشترك من<fieldset>و<legend>؛ ومن دونهما يسمع المستخدم «نعم، زر اختيار» دون أن يعرف ما السؤال. - الجداول:
<table>للبيانات ذات الصفوف والأعمدة، مع<th scope="col">أو<th scope="row">للرؤوس و<caption>للعنوان. عندها تربط الشجرة كل خلية بيانات برؤوسها، فحين ينتقل المستخدم من خلية إلى أخرى يعلن قارئ الشاشة الرأس الذي تغيّر، كاسم العمود قبل كل قيمة، ويستطيع المستخدم التنقل على طول صف أو عمود. أما شبكة من عناصر<div>، أو جدول رؤوسه خلايا<td>بخط عريض، فتفقد هذه العلاقات وتخفق في 1.3.1. والخطأ المعاكس موجود أيضاً:<table>مستخدم للتخطيط، فقد يعلن صفوفاً وأعمدة بلا معنى.
مثال تطبيقي: صفحة الدفع نفسها بترميزين
تعرض مكتبة مكوّنات الواجهة الأمامية صفحة الدفع بالترميز A أدناه: كل عنصر فيه، ما عدا حقل الإدخال نفسه، <div> بفئة (class) منسّق ليبدو عنواناً أو قائمة تنقل أو تسمية حقل أو جدول ملخص أو زراً. وتنجح مراجعة التصميم، لأن الصفحة على الشاشة لا تختلف عن الترميز B الذي يستخدم عنصراً دلالياً واحداً لكل بنية.
افتح الترميزين في أدوات المطور في المتصفح (انقر بزر الفأرة الأيمن على عنصر واختر «Inspect»؛ وفي Chrome وEdge يعرض تبويب «Accessibility»، الموجود في صف التبويبات نفسه مع «Styles»، دور العنصر المحدد واسمه المحسوب) وسترى الفرق فوراً. في A، «Checkout» عقدة عامة فيها نص، فقائمة العناوين فارغة؛ وقائمة التنقل عنصران عامان لا يصل إليهما Tab أبداً؛ وحقل الإدخال بلا اسم؛ و«Total» و«600 SAR» نصّان غير مترابطين؛ و«Place order» عقدة عامة لا يفعّلها إلا الفأرة. وفي B تُظهر الشجرة عنواناً من المستوى 1 «Checkout»، ومعلم تنقل يحوي قائمة من رابطين، ومعلم main، ومربع نص مطلوباً اسمه «Postal code»، وجدولاً تُربط فيه «600 SAR» برأس صفها «Total»، وزراً اسمه «Place order» يصل إليه Tab ويفعّله Enter أو Space. لم يتغير شيء بصرياً، وتغير كل شيء للتقنيات المساعدة.
<!-- A: div soup -->
<div class="title">Checkout</div>
<div class="menu">
<div class="item" onclick="go('/orders')">Orders</div>
<div class="item" onclick="go('/addresses')">Addresses</div>
</div>
<div class="hint">Postal code</div>
<input class="zip">
<div class="row"><div class="cell">Total</div><div class="cell">600 SAR</div></div>
<div class="btn" onclick="pay()">Place order</div>
<!-- B: semantic HTML, identical on screen -->
<nav>
<ul>
<li><a href="/orders">Orders</a></li>
<li><a href="/addresses">Addresses</a></li>
</ul>
</nav>
<main>
<h1>Checkout</h1>
<form action="/orders" method="post">
<label for="zip">Postal code</label>
<input id="zip" name="zip" required>
<table>
<caption>Order summary</caption>
<tr><th scope="row">Total</th><td>600 SAR</td></tr>
</table>
<button type="submit">Place order</button>
</form>
</main>A: ترميز div فقطيبدو صحيحاً
كل بنية <div> منسّق بفئة، ما عدا حقل الإدخال
- قائمة العناوين:
- فارغة: «Checkout» نص عامفشل
- المعالم:
- لا شيء: عناصر div عامة فقطفشل
- قائمة التنقل (Orders وAddresses):
- سطرا نص؛ لا يصل إليهما Tab أبداًفشل
- حقل الرمز البريدي:
- مربع نص بلا اسمفشل
- إجمالي الطلب:
- «Total» و«600 SAR» نصّان غير مترابطينفشل
- عنصر التحكم «Place order»:
- عقدة عامة؛ بالفأرة فقطفشل
B: HTML الدلاليةويُقرأ صحيحاً أيضاً
عنصر أصلي واحد لكل بنية، والمظهر نفسه على الشاشة
- قائمة العناوين:
- عنوان من المستوى 1 «Checkout»نجاح
- المعالم:
- navigation وmainنجاح
- قائمة التنقل (Orders وAddresses):
- قائمة من رابطين، كلاهما قابل للتركيزنجاح
- حقل الرمز البريدي:
- مربع نص «Postal code»، مطلوبنجاح
- إجمالي الطلب:
- الخلية «600 SAR» مرتبطة برأس صفها «Total»نجاح
- عنصر التحكم «Place order»:
- زر؛ يصل إليه Tab ويفعّله Enter أو Spaceنجاح
يصف كل صف شجرة إمكانية الوصول كما تعرضها لوحة إمكانية الوصول في أدوات المطور.
أخطاء شائعة
- الحكم على إمكانية الوصول من الشاشة. فالصفحة التي تبدو صحيحة قد تكون شجرة إمكانية الوصول فيها شبه فارغة؛ افحص الشيفرة أو لوحة إمكانية الوصول، لا البكسلات.
- معاملة كل ما هو قابل للنقر بالطريقة نفسها:
<div onclick>ليس زراً، و<a>بلاhrefليس رابطاً، و<button>ينتقل إلى صفحة أخرى يجب أن يكون رابطاً. - قبول النص النائب تسميةً، أو قبول
<label>تشير سمتهforإلىidغير موجود في الصفحة. - فحص شكل العناوين بدلاً من ماهيتها: قد تحوي الصفحة ستة أسطر كبيرة بخط عريض ولا تحوي
<h1>واحداً. - الإبلاغ بعبارة «غير قابل للوصول لقارئات الشاشة» دون ذكر الدور والاسم: العيب المفيد يذكر ما تكشفه الشجرة، وما يجب أن تكشفه، ومعيار النجاح الذي يخفق فيه.
- اللجوء إلى ARIA لإصلاح
<div>في حين أن عنصراً أصلياً يمنح الدور والاسم وسلوك لوحة المفاتيح والحالات بتغيير واحد.
من منظور ضمان الجودة
في الفريق، تُفحص الدلالات في أبكر مرحلة من المراجعة. فحين يظهر مكوّن جديد أو قالب صفحة في طلب دمج (Pull Request) أو في تحديث لنظام التصميم، اقرأ شيفرته قبل أي جلسة اختبار: عناوين حقيقية، و<button> لكل إجراء، و<label> لكل حقل، و<th> في جداول البيانات. اتفق على هذه التوقعات مع مطوّر الواجهة الأمامية واكتبها في تعريف الإنجاز (Definition of Done)، فيجري الفحص في مراجعة الشيفرة بدلاً من أن يظهر ملاحظةً بعد أسابيع.
وحين تختبر صفحة مبنية، افتح لوحة إمكانية الوصول في أدوات المطور لتقرأ دور كل عنصر تحكم واسمه المحسوب، واضغط Tab عبر الصفحة لتتأكد من أن كل عنصر تحكم يمكن الوصول إليه، وقارن العناوين المرئية بالعناوين في الشجرة. وسجّل كل عيب مع العنصر كما يُعرض، والدور والاسم اللذين تكشفهما الشجرة، والعنصر المتوقع، ومعيار النجاح، وهو غالباً 1.3.1 أو 4.1.2. ويبني دليلا لوحة المفاتيح وقارئ الشاشة التاليان على هذه الطبقة بالذات: فحين تكون الدلالات خاطئة، يفشل كل اختبار لاحق للسبب الجذري نفسه.
تمرين عملي
راجع ترميز بطاقة منتج
تعرض قائمة منتجات بطاقات فيها اسم المنتج بخط كبير، وتقييم بالنجوم، وسعر، وعنصر تحكم «Add to cart»، وعنصر تحكم «Details» يفتح صفحة المنتج. وترميز المطوّر لبطاقة واحدة أدناه. دون قارئ شاشة، اكتب ما ستكشفه شجرة إمكانية الوصول لكل جزء، وسمِّ العيوب مع معيار WCAG 2.2 الذي يخفق فيه كل منها، واذكر العنصر الدلالي الذي تتوقعه بدلاً منه.
ثم اكتب حالة اختبار واحدة للبطاقة المصحّحة يستطيع مختبِر لا يملك سوى لوحة المفاتيح تنفيذها.
<div class="card">
<div class="name">Wireless keyboard</div>
<div class="rating">★★★★☆</div>
<div class="price">249 SAR</div>
<span class="btn" onclick="addToCart(42)">Add to cart</span>
<a class="btn" onclick="openProduct(42)">Details</a>
</div>- تتبّع البطاقة من أعلاها إلى أسفلها واكتب الدور والاسم اللذين سيكونان لكل عنصر في شجرة إمكانية الوصول.
- علّم كل موضع يكون فيه الدور عاماً أو الاسم مفقوداً أو مضلّلاً.
- اختر العنصر الأصلي الذي يمنح الدور والاسم وسلوك لوحة المفاتيح الصحيح لكل منها.
- اكتب حالة اختبار لوحة المفاتيح بخطواتها ونتيجة متوقعة لكل خطوة.
إظهار الإجابة النموذجية
الشجرة اليوم: خمس عقد عامة فيها نص. اسم المنتج ليس عنواناً، فلا يمكن العثور على البطاقة من قائمة العناوين (1.3.1). والتقييم لا ينقل قيمته إلا برموز النجوم؛ وسواء قرأ قارئ الشاشة «نجمة سوداء» أربع مرات و«نجمة بيضاء» مرة واحدة أو تخطى الرموز، فعلى المستخدم أن يستنتج بنفسه، لذا يلزم مكافئ نصي مثل «4 من 5 نجوم» (1.1.1 المحتوى غير النصي (Non-text Content): تعدّ WCAG نمط الحروف الذي لا يعبّر عن لغة بشرية، كهذه النجوم، محتوى غير نصي مثل الأيقونة أو الصورة). و«Add to cart» عنصر <span> بلا دور وغير قابل للتركيز، فلا يستطيع مستخدم لوحة المفاتيح إضافة المنتج (4.1.2 و2.1.1 لوحة المفاتيح). و«Details» عنصر <a> بلا href، فهو ليس رابطاً وغير قابل للتركيز وغائب عن قائمة الروابط (4.1.2 و2.1.1).
الترميز المتوقع: كل بطاقة <li> داخل <ul> للمنتجات، والاسم عنوان بالمستوى المناسب (مثلاً <h3> تحت <h2> «Results»)، والمكافئ النصي «4 من 5 نجوم» (مثلاً صورة <img> للنجوم مع alt="4 of 5 stars"، أو نص مرئي مع حذف رموز النجوم من شجرة إمكانية الوصول بالسمة aria-hidden="true")، و<button type="button">Add to cart</button>، و<a href="/products/42">Details</a>. ولأن كل بطاقة تكرر أسماء عناصر التحكم نفسها، دوّن سؤال متابعة: كيف سيعرف مستخدم قارئ الشاشة إلى أي منتج ينتمي «Add to cart»؟ ويجيب عنه دليل اختبار قارئات الشاشة في قسم «فحص الأسماء والتسميات والأوصاف عملياً».
حالة اختبار لوحة المفاتيح. الشرط المسبق: قائمة المنتجات مفتوحة وفيها بطاقة واحدة على الأقل. الخطوة 1: اضغط Tab من بداية الصفحة حتى يصل التركيز إلى البطاقة الأولى؛ المتوقع: حلقة تركيز مرئية على «Add to cart». الخطوة 2: اضغط Enter؛ المتوقع: يزداد عداد السلة بواحد. الخطوة 3: اضغط Space؛ المتوقع: يزداد عداد السلة بواحد مرة أخرى، لأن الزر يستجيب للمفتاحين كليهما. الخطوة 4: اضغط Tab؛ المتوقع: ينتقل التركيز إلى «Details». الخطوة 5: اضغط Enter؛ المتوقع: تُفتح صفحة منتج لوحة المفاتيح اللاسلكية.
أسئلة شائعة
هل تكفي HTML الدلالية لمطابقة الصفحة معايير WCAG؟
لا. فهي تغطي جزءاً كبيراً من 1.3.1 و4.1.2 وتمنح التشغيل بلوحة المفاتيح مجاناً، لكن التباين والبدائل النصية والتركيز المرئي ورسائل الخطأ ومعايير كثيرة أخرى تبقى. الدلالات هي الأساس الذي تفترضه الفحوص الأخرى.
هل أستطيع اختبار الدلالات دون قارئ شاشة؟
معظمها، نعم. تُظهر لوحة إمكانية الوصول في أدوات المطور دور أي عنصر واسمه المحسوب، ويُظهر مفتاح Tab ما هو قابل للتركيز، ويُظهر مخطط العناوين البنية. أما جلسة قارئ الشاشة، التي يتناولها دليل لاحق، فتؤكد ما يسمعه المستخدمون فعلاً وتكشف ما لا تستطيع الشجرة وحدها إظهاره.
إذا كان لعنصر <div> السمة role="button"، فهل يساوي <button>؟
فقط بعد أن يضيف المطور قابلية التركيز ومعالجة Enter وSpace وحالة التعطيل يدوياً، ويحافظ على عمل كل ذلك. فالعنصر الأصلي يحوي هذا كله مدمجاً ومختبراً في كل متصفح، ولهذا تنص القاعدة الأولى لاستخدام ARIA على تفضيله. ويتناول درس ARIA متى يكون الدور هو الخيار الصحيح.
المراجع
- Web Content Accessibility Guidelines (WCAG) 2.2توصية W3C التي تحدد معايير النجاح القابلة للاختبار لإتاحة محتوى الويب، مرتّبةً تحت أربعة مبادئ وثلاثة مستويات مطابقة (A وAA وAAA).
- HTML Living Standardلغة HTML، بما فيها مراجع المحارف المسماة (الكيانات) وقواعد التحليل التي تتبعها المتصفحات.
- Accessible Name and Description Computation 1.2كيف تحسب المتصفحات الاسم والوصف الميسَّرين لعنصرٍ من التسميات وسمات ARIA والمحتوى (مسودة عمل من W3C).
- Understanding WCAG 2.2الشرح التوضيحي لكل إرشاد ومعيار نجاح في WCAG 2.2: الغرض، ومن يستفيد، والأمثلة والتقنيات (غير إلزامي).
تدرّب بأدوات متقن
تجميل HTML بمسافات بادئة صحيحة للعناصر المتداخلة، مع الحفاظ على كتل pre وscript وstyle.
ولّد حالات اختبار منظّمة (المعرّف والعنوان والشروط المسبقة والخطوات والنتيجة المتوقّعة والأولوية) من وصف الميزة وقائمة الحقول.
ولّد قائمة تحقق QA مخصّصة (وظيفية وواجهة مستخدم وAPI وأمان وأداء وإمكانية وصول وإصدار) لأي ميزة باستخدام الذكاء الاصطناعي من متقن.
للتعمّق أكثر
تقدّمك في هذا الموضوع
سجّل الدخول لتتابع تقدّمك
علّم الموضوعات مكتملة، وتابع من حيث توقفت، وافتح امتحانات التخصص.