الوحدة 3 · لوحة المفاتيح والتركيز وARIA
ARIA: الأدوار والحالات والـ Live Regions
18 دقراءة 4 دبيئة تجريب الكود
الدرس في لمحة
طبّق ARIA فقط حيث يقصر HTML، وأبقِ حالات مثل aria-pressed وaria-expanded متزامنة، وأعلن التحديثات الديناميكية عبر live regions من نوع status وalert.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
كل ما سبق استخدم HTML عاديًا، وهذا مقصود. عناصر HTML تأتي ومعها الأدوار والأسماء والحالات وسلوك لوحة المفاتيح جاهزة. لكن أحيانًا ينفد ما في HTML. لا يوجد عنصر أصلي لحالة الضغط في زر التبديل، ولا لمجموعة تبويبات، ولا لـ «قل هذا بصوت عالٍ حين تتغيّر السلة». هنا يأتي دور ARIA (Accessible Rich Internet Applications): مجموعة من الخصائص تتيح لك وصف الأدوار والحالات والعلاقات مباشرةً لشجرة إمكانية الوصول.
القاعدة الأولى في ARIA
تبدأ إرشادات W3C نفسها بقاعدة تفاجئ الناس: إن استطعت استخدام عنصر HTML أصلي فيه السلوك الذي تحتاجه، فاستخدمه بدلًا من ARIA. وتظلّ فحوص WebAIM السنوية لأشهر مليون صفحة رئيسية تجد أن الصفحات التي تستخدم ARIA فيها أخطاء مرصودة أكثر، لا أقل. والسبب بسيط. ARIA تغيّر فقط ما يُعلَن. لا تجعل أي شيء قابلًا للتركيز، ولا تضيف معالجة للوحة المفاتيح، ولا تغيّر المظهر. كل خاصية ARIA وعدٌ للتقنيات المساعدة، وعلى كود JavaScript الذي تكتبه أن يفي به.
<!-- A promise with nothing behind it -->
<span role="button">Add to basket</span>
<!-- The same promise, kept by the browser -->
<button type="button">Add to basket</button>الأدوار والخصائص والحالات
تنقسم خصائص ARIA (attributes) إلى ثلاث مجموعات.
الأدوار (roles) تقول ما هو الشيء: role="tab"، role="dialog"، role="switch"، role="status". ونادرًا ما تحتاج إليها لأشياء يوفّرها HTML أصلًا.
الخصائص بالمعنى الدقيق (properties) تصف العلاقات أو السمات الثابتة: aria-labelledby وaria-describedby (استخدمتهما كلتيهما في النماذج)، وaria-controls، وaria-required، وaria-haspopup.
الحالات (states) تصف أشياء تتغيّر مع تفاعل المستخدم، ويجب أن يحدّثها السكربت: aria-expanded، aria-pressed، aria-checked، aria-selected، aria-current، aria-disabled، aria-invalid.
قلب قائمة الأمنيات في Ticketly مثال جيد. إنه زر حقيقي أصلًا، لكن لا شيء يخبر قارئ الشاشة إن كانت الفعالية محفوظة أم لا. تحوّله aria-pressed إلى زر تبديل (toggle button):
<button type="button" class="fav" aria-pressed="false">Save to wishlist</button>fav.addEventListener('click', () => {
const saved = fav.getAttribute('aria-pressed') === 'true';
fav.setAttribute('aria-pressed', String(!saved));
});صار NVDA يقول “Save to wishlist, toggle button, not pressed”، ثم “pressed” بعد التفعيل. لاحظ أن التسمية تبقى كما هي؛ والحالة هي التي تحمل التغيير. ويمكنك التنسيق انطلاقًا من الحالة مباشرةً، وهذا يمنع المظهر والدلالة من الافتراق:
.fav[aria-pressed='true'] {
background: #5b3cc4;
color: #fff;
}وللصفحة الحالية في قائمة تنقّل، تخبر aria-current="page" مستخدمي قارئ الشاشة بالرابط الذي هم عليه: “Tickets, current page, link”.
وبضع قواعد أخرى من مذكّرة “Using ARIA” الصادرة عن W3C تُبعدك عن المتاعب:
- لا تغيّر الدلالات الأصلية إلا إذا اضطررت فعلًا:
<h2 role="button">يدمّر العنوان. ضع زرًّا داخل العنوان بدلًا من ذلك. - كل عنصر تحكّم تفاعلي مبني بـ ARIA يجب أن يكون قابلًا للتشغيل بلوحة المفاتيح.
- كل عنصر تفاعلي يحتاج إلى اسم متاح.
الـ Live Regions: إعلان التغييرات
حين يضيف Ticketly تذكرة، يتغيّر عدّاد السلة في الترويسة من 1 إلى 2. يلاحظ المبصرون ذلك. أما مستخدمو قارئ الشاشة فلا يسمعون شيئًا، لأن تركيزهم ما زال على الزر الذي ضغطوه. الـ live region عنصر تُقرأ تغييرات محتواه تلقائيًا، دون نقل التركيز.
<p id="basket-status" role="status"></p>function addToBasket() {
count += 1;
basketStatus.textContent = `Ticket added. ${count} tickets in your basket.`;
}ثلاث قواعد تجعل الـ live regions موثوقة:
- يجب أن تكون المنطقة موجودة قبل التغيير. تراقب قارئات الشاشة الـ live regions الموجودة بحثًا عن تغييرات. وإدراج عنصر جديد يحتوي نصًا أصلًا كثيرًا ما يفوتها. اعرض المنطقة فارغةً عند تحميل الصفحة.
- اختر الدرجة: مهذّبة أم حازمة.
role="status"(مثلaria-live="polite") تنتظر حتى ينتهي قارئ الشاشة من جملته الحالية. وrole="alert"(حازمة، assertive) تقاطعه. احتفظ بالـ alert للرسائل العاجلة والنادرة مثل فشل الدفع؛ فإعلان “Ticket added” بحزم مع كل نقرة مُرهِق. - اجعل الرسائل قصيرة وذات معنى. أعلن النتيجة (“2 tickets in your basket”)، لا الآلية (“basket component updated”).
تصبح حالات ARIA وأدوارها في أقوى صورها في الـ widgets المخصّصة، حيث لا يوجد أي عنصر HTML مقابل. يبني الدرس التالي ثلاثة منها وفق دليل ARIA Authoring Practices.
أهم النقاط
- القاعدة الأولى في ARIA أن تستخدم عنصر HTML أصليًا حين يوجد؛ فـ ARIA تغيّر ما يُعلَن، ولا تغيّر أبدًا كيف يتصرّف أي شيء.
- تنقسم ARIA إلى أدوار (ما هو العنصر)، وخصائص (العلاقات والسمات الثابتة)، وحالات (قيم تتغيّر، ويجب أن يُبقيها السكربت متزامنة).
- لا تضع أبدًا aria-hidden=“true” على عنصر قابل للتركيز، ولا تتجاوز دور عنصر أصلي له الدور الصحيح أصلًا.
- يجب أن تكون الـ live region موجودة في الـ DOM قبل أن يتغيّر نصها؛ استخدم role=“status” للتحديثات المهذّبة، وrole=“alert” للعاجلة فقط.