ما هو ARIA؟

ARIA (تطبيقات الإنترنت الغنية القابلة للوصول) هي مواصفة W3C التي تسمح بتحسين إمكانية الوصول لتطبيقات الويب الغنية والمكونات الديناميكية.ARIA (Accessible Rich Internet Applications)

🏷️ الأدوار

تحدد ما هو العنصر (زر، تنقل، تنبيه...)

role="button"

📊 الحالات

تصف الحالة الحالية للعنصر (محدد، موسع، معطل...)

aria-expanded="true"

🔧 الخصائص

توفر معلومات إضافية (تسمية، describedby، controls...)

aria-label="القائمة الرئيسية"

⚠️ القاعدة الذهبية ARIA

لا تستخدم ARIA إذا كان بإمكانك استخدام HTML الأصلي

النماذج مع سمات ARIA

مثال سيء

نموذج بدون ARIA

❌ نموذج غير قابل للوصول بدون سمات ARIA المناسبة:

<!-- سيء: لا توجد تسمية، لا يوجد وصف -->
<input type="text" placeholder="بريدك الإلكتروني">

<!-- سيء: الأيقونة غير قابلة للوصول -->
<button>
  <span class="icon">🔍</span>
</button>

<!-- سيء: خطأ غير مرتبط، لا يوجد إكمال تلقائي -->
<input type="password">
<div class="error">كلمة المرور قصيرة جدًا</div>
كلمة المرور قصيرة جدًا
أوافق على شروط الاستخدام

مثال جيد

نموذج مع ARIA

✅ نموذج يمكن الوصول إليه مع سمات ARIA المناسبة:

<!-- جيد: aria-label للحقل بدون تسمية مرئية -->
<input
  type="text"
  aria-label="عنوان البريد الإلكتروني (مطلوب)"
  aria-describedby="email-desc"
  aria-required="true">
<span id="email-desc">التنسيق: name@example.com</span>

<!-- جيد: زر مع aria-label -->
<button aria-label="إرسال النموذج">
  <span aria-hidden="true">🔍</span>
</button>

<!-- جيد: خطأ مرتبط مع aria-describedby -->
<input
  type="password"
  aria-label="كلمة المرور (8 أحرف كحد أدنى)"
  aria-invalid="true"
  aria-describedby="pwd-error"
  autocomplete="new-password">
<div id="pwd-error" role="alert">
  يجب أن تحتوي كلمة المرور على 8 أحرف على الأقل
</div>
التنسيق: name@example.com
8 أحرف كحد أدنى مع أرقام وأحرف
خيارات الإشعارات
تلقي التحديثات المهمة عبر البريد الإلكتروني
تلقي التنبيهات العاجلة عبر الرسائل القصيرة
سمات ARIA المستخدمة:
  • aria-label: يوفر تسمية يمكن الوصول إليها
  • aria-describedby: يربط وصفًا مفصلاً
  • aria-required: يشير إلى حقل مطلوب
  • aria-invalid: يشير إلى حقل غير صالح
  • aria-labelledby: يشير إلى تسمية موجودة
  • role="alert": يعلن عن الأخطاء على الفور
  • aria-hidden: يخفي العناصر الزخرفية
  • aria-live: يعلن عن التغييرات الديناميكية

الشرح: تعمل سمات ARIA على إثراء النماذج من خلال توفير التسميات والأوصاف والحالات للتقنيات المساعدة.

أكورديون يمكن الوصول إليه

مثال سيء

بدون سمات ARIA

ما هي إمكانية الوصول إلى الويب؟+
لماذا هي مهمة؟+
كيف تبدأ؟+
<!-- سيء: لا توجد سمات ARIA، لا يوجد تنقل بلوحة المفاتيح -->
<div class="accordion-header" @click="toggle">
  <span>Title</span>
  <span>+</span>
</div>
<div v-if="open">
  Content
</div>

مثال جيد

مع ARIA المناسب

<!-- جيد: ARIA كامل مع التنقل بلوحة المفاتيح -->
<button
  id="accordion-button-1"
  aria-expanded="false"
  aria-controls="panel-1"
  @click="toggle"
  @keydown.enter="toggle"
>
  Title
</button>
<div
  id="panel-1"
  role="region"
  aria-labelledby="accordion-button-1"
  :hidden="!open"
>
  Content
</div>

الشرح: يجب أن يستخدم الأكورديون سمات ARIA المناسبة، ويدعم التنقل بلوحة المفاتيح ويعلن عن تغييرات الحالة.

Tabindex والتنقل بلوحة المفاتيح

تتحكم سمة tabindex في ما إذا كان العنصر يمكن أن يتلقى التركيز بلوحة المفاتيح وبأي ترتيب.

✅ tabindex="0"

العنصر قابل للتركيز في ترتيب DOM الطبيعي

tabindex="0"
<!-- جيد: عنصر تفاعلي قابل للتركيز -->
<div role="button" aria-label="Custom action" tabindex="0">
  Custom button
</div>

⚠️ tabindex="-1"

قابل للتركيز بواسطة JavaScript ولكن ليس بواسطة Tab

tabindex="-1"
<!-- جيد: للتركيز البرمجي -->
<div role="alert" aria-live="assertive" tabindex="-1">
  Error message
</div>

❌ tabindex > 0

يغير ترتيب التنقل (تجنب!)

tabindex="5"
<!-- سيء: يكسر ترتيب Tab الطبيعي -->
<button tabindex="3">Third</button>
<button tabindex="1">First</button>
<button tabindex="2">Second</button>

📋 أفضل ممارسات Tabindex

  • استخدم tabindex="0" لجعل العناصر التفاعلية المخصصة قابلة للتركيز
  • استخدم tabindex="-1" للتركيز البرمجي (النوافذ المنبثقة، التنبيهات)
  • لا تستخدم أبدًا قيمًا موجبة - احترم ترتيب DOM
  • العناصر التفاعلية الأصلية (<button>، <a>، <input>) لا تحتاج إلى tabindex

🎯 أمثلة تفاعلية

اختبر التنقل بلوحة المفاتيح (Tab/Shift+Tab) مع هذه العناصر:

✅ عناصر قابلة للتركيز

رابط
زر مخصص (div)

❌ عناصر غير قابلة للتركيز

نص بسيط (div)
نص مضمن (span)

فقرة

💡 نصائح الاختبار

  • استخدم Tab للتنقل للأمام
  • استخدم Shift + Tab للتنقل للخلف
  • استخدم Space أو Enter لتنشيط العناصر
  • لاحظ مؤشر التركيز (الخطوط الزرقاء)
  • لاحظ العناصر التي يمكن أو لا يمكن أن تتلقى التركيز

قائمة منسدلة يمكن الوصول إليها

مثال سيء

مثال جيد

الشرح: يجب أن تدعم القائمة المنسدلة التنقل بلوحة المفاتيح، والإغلاق بمفتاح Escape، والحفاظ على التركيز بشكل مناسب.

معرض صور يمكن الوصول إليه

مثال سيء

مثال جيد

الشرح: يجب أن يسمح معرض الصور بالتنقل بلوحة المفاتيح وتوفير أوصاف سياقية لكل صورة. نمط ARIA tablist/tab/tabpanel مثالي لهذه الحالة.

جدول قابل للفرز يمكن الوصول إليه

مثال سيء

الاسم ↑البريد الإلكتروني الدور الحالة
أليس مارتنalice@example.comمديرنشط
بوب دوبونتbob@example.comمستخدمغير نشط
تشارلي لورويcharlie@example.comمشرفنشط
ديانا موروdiana@example.comمستخدممعلق

مثال جيد

أليس مارتنalice@example.comمديرنشط
بوب دوبونتbob@example.comمستخدمغير نشط
تشارلي لورويcharlie@example.comمشرفنشط
ديانا موروdiana@example.comمستخدممعلق
انقر على رؤوس الأعمدة لفرز الجدول. استخدم Tab للتنقل بين أزرار الفرز.

الشرح: يجب أن يشير الجدول القابل للفرز إلى حالة الفرز الحالية، والسماح بالتنقل بلوحة المفاتيح، والإعلان عن التغييرات لقارئات الشاشة.

مناطق aria-live الديناميكية

مثال سيء

بدون aria-live

لا يتم الإعلان عن التغييرات

<!-- Mauvais : pas d'attribut aria-live -->
<div class="status-banner">
  <p></p>
</div>

العداد: 0

المشاكل:

  • لا يتم الإعلان عن التغييرات
  • مستخدمو قارئ الشاشة لا يعرفون أن المحتوى تغير
  • لا يوجد إشارة إلى أهمية الرسالة

مثال جيد

مع aria-live المناسب

يتم الإعلان عن التغييرات وفقًا لأولويتها

<!-- Bon : avec aria-live="polite" pour informations -->
<div
  class="status-banner"
  aria-live="polite"
  aria-atomic="true"
  role="status"
>
  <p>Information : Données mises à jour</p>
</div>

<!-- Bon : avec aria-live="assertive" pour alertes -->
<div
  class="alert-banner"
  aria-live="assertive"
  aria-atomic="true"
  role="alert"
>
  <p>Attention : Action requise immédiatement</p>
</div>

منطقة Polite (معلومات)

المزايا:

  • الرسائل المهمة تقاطع مع aria-live="assertive"
  • الرسائل الإعلامية تنتظر مع aria-live="polite"
  • aria-atomic="true" يعلن عن محتوى المنطقة بالكامل
  • الأدوار المناسبة (status، alert) توفر المزيد من السياق

الشرح: تسمح مناطق Aria-live بالإعلان عن تغييرات المحتوى لقارئات الشاشة. 'polite' ينتظر انتهاء الإعلان الحالي، 'assertive' يقاطع على الفور.

أزرار الأيقونات القابلة للوصول

مثال سيء

أزرار بدون وصف

هذه الأزرار ليس لها إشارة نصية:

المشاكل:
  • قارئات الشاشة تعلن فقط "زر"
  • من المستحيل معرفة الإجراء دون رؤية الأيقونة
  • يمكن تفسير الرموز التعبيرية بشكل خاطئ
  • لا توجد تلميحة عند التمرير

مثال جيد

أزرار يمكن الوصول إليها

عدة طرق لجعل الأيقونات قابلة للوصول:

1. مع aria-label
2. مع نص مرئي
3. مع نص مخفي بصريًا
أفضل الممارسات:
  • قدم دائمًا نصًا بديلاً (aria-label، نص مخفي، أو نص مرئي)
  • استخدم aria-hidden="true" على الأيقونات الزخرفية
  • أضف تلميحات مع سمة title
  • فضل النص المرئي عندما تسمح المساحة

الشرح: يجب أن تحتوي الأزرار التي تحتوي على أيقونات فقط على aria-label أو نص مخفي بصريًا ليتم فهمها بواسطة قارئات الشاشة.

Combobox / بحث مع اقتراحات

مثال سيء

بدون ARIA أو التنقل بلوحة المفاتيح

مثال جيد

مع ARIA والتنقل بلوحة المفاتيح

0 نتيجة/نتائج متاحة

الشرح: يجب أن يكون البحث مع الاقتراحات (combobox) قابلاً للتنقل بلوحة المفاتيح، وإعلان النتائج والسماح بالاختيار.

إشعارات Toast (المناطق الحية)

مثال سيء

بدون aria-live

❌ لا يتم الإعلان عن الإشعارات لقارئات الشاشة

<!-- سيء: لم يتم الإعلان عنه لقارئات الشاشة -->
<div v-if="showToast" class="toast">
  Votre demande a été enregistrée
</div>

مثال جيد

مع aria-live المناسب

✅ يتم الإعلان عن الإشعارات بشكل صحيح

<!-- جيد: إشعار معلومات (polite) -->
<div
  v-if="showToast"
  role="status"
  aria-live="polite"
  aria-atomic="true"
  class="toast"
>
  <p>Votre demande a été enregistrée</p>
  <button @click="dismiss" aria-label="Fermer notification">✕</button>
</div>

<!-- جيد: تنبيه خطأ (assertive) -->
<div
  v-if="showError"
  role="alert"
  aria-live="assertive"
  aria-atomic="true"
  class="toast error"
>
  <p>Erreur : action impossible à exécuter</p>
  <button @click="dismiss" aria-label="Fermer alerte">✕</button>
</div>
الفروقات:
  • role="status" + aria-live="polite": للإشعارات الإعلامية، لا يقاطع القراءة الحالية
  • role="alert" + aria-live="assertive": للأخطاء الحرجة، يقاطع على الفور
  • aria-atomic="true": يعلن عن محتوى الإشعار بالكامل

الشرح: يجب الإعلان عن الإشعارات الديناميكية لقارئات الشاشة دون سرقة التركيز. استخدم role='status' للمعلومات و role='alert' للأخطاء.