موقعنا كان “أخرس”: قصة إضافة صوت لتجربة المستخدم بسمات ARIA

كنت قاعد في مكتبي، مرتاح ومتكي على الكرسي، وبشرب فنجان القهوة السادة اللي ما بقدر أبدأ يومي بدونه. كنت براجع كود كتبته امبارح لمشروع جديد شغالين عليه. فجأة، وصلني إيميل شد انتباهي. الإيميل كان من شب اسمه “خالد”، مستخدم كفيف، بحب شغلنا وبتابعنا من زمان.

خالد كان لطيف جداً في كلامه، بدأ الإيميل بمدح الشغل اللي بنقدمه، لكن بعدها حكى جملة ضلت ترن في بالي أيام: “موقعكم الجديد يا أبو عمر، زي مدينة جميلة جداً، بس شوارعها بدون أسماء أو إشارات مرور. أنا بحاول أتجول فيها، بس للأسف أنا ضايع تماماً”.

هاي الجملة كانت زي صفعة صحّتني. إحنا، في خضم حماسنا للتصميمات العصرية والـ “Animations” المعقدة، نسينا فئة مهمة جداً من مستخدمينا. موقعنا كان جميل بصرياً، لكنه كان “أخرس” تماماً بالنسبة لخالد وأي شخص بيستخدم قارئ شاشة (Screen Reader). في تلك اللحظة، قررت إن هذا الوضع لازم يتغير. ومن هنا بدأت رحلتنا لإعطاء “صوت” لموقعنا.

ما هي الوصولية (Accessibility) وليش هي مهمة؟

قبل ما نخوض في التفاصيل التقنية، خلينا نحكي شوي عن “الوصولية” أو كما تعرف بـ a11y (لأن بين حرفي a و y يوجد 11 حرفاً). الوصولية الرقمية ببساطة هي تصميم وتطوير المواقع والتطبيقات بحيث يمكن لجميع الناس استخدامها، بغض النظر عن قدراتهم أو إعاقاتهم.

هذا الموضوع مش بس بخُص المستخدمين ذوي الإعاقات الدائمة (مثل خالد الكفيف)، بل يمتد ليشمل أي شخص ممكن يواجه إعاقة مؤقتة أو ظرفية. فكر فيها:

  • شخص إيده مكسورة (إعاقة مؤقتة) ويجد صعوبة في استخدام الماوس.
  • أب يحمل طفله بيد ويحاول تصفح الموقع بيد واحدة (إعاقة ظرفية).
  • شخص في مكان عام صاخب ولا يستطيع سماع الفيديو (إعاقة ظرفية).
  • مستخدم لديه اتصال إنترنت بطيء جداً والصور لا تظهر.

لما تصمم للوصولية، أنت فعلياً بتصمم تجربة أفضل للجميع. المعيار العالمي لهذا المجال هو WCAG (Web Content Accessibility Guidelines)، وهو اللي بيعطينا خارطة الطريق. مشكلتنا مع خالد كانت انتهاكاً واضحاً لأبسط مبادئ هاي الإرشادات.

دخلنا عالم ARIA: شو هالأشي أصلاً؟

لما بدأنا نبحث عن حل، كان مصطلح ARIA يظهر في كل مكان. ARIA هي اختصار لـ Accessible Rich Internet Applications. ببساطة، هي مجموعة من السمات (Attributes) اللي بنقدر نضيفها لعناصر HTML عشان “نحكي” مع التقنيات المساعدة (مثل قارئات الشاشة) ونعطيها معلومات إضافية ما بتقدر تعرفها من HTML لوحده.

بحب أشبهها باللافتات الإرشادية بلغة بريل في المباني. المبنى هو موقعك (HTML)، والأشخاص المبصرون بيقدروا يقرأوا اللافتات العادية. لكن الشخص الكفيف بيحتاج للافتات بريل (ARIA) عشان يعرف إنه هذا باب الحمام، وهذا زر المصعد.

ثلاثية ARIA: الأدوار، الخصائص، والحالات

سمات ARIA بتنقسم بشكل أساسي لثلاث فئات، وفهمهم هو مفتاح كل شيء:

  1. الأدوار (Roles): بتحدد شو هو العنصر أو وظيفته. مثلاً، لو استخدمت <div> عشان تعمل زر، قارئ الشاشة ما رح يعرف إنه زر. هون بيجي دور role="button" عشان يخبره: “اسمع، هذا مش مجرد div، هذا زر!”.
  2. الخصائص (Properties): بتوصف العنصر. أشهر وأهم خاصية هي aria-label. هاي الخاصية بتعطي اسم أو “تسمية” للعنصر بيقرأها قارئ الشاشة.
  3. الحالات (States): بتوصف الحالة الحالية للعنصر، وهل هي متغيرة. مثلاً، هل القائمة المنسدلة مفتوحة أم مغلقة؟ (aria-expanded="true/false")، هل العنصر محدد حالياً؟ (aria-selected="true").

رحلتنا العملية: كيف “تكلمنا” مع قارئ الشاشة؟

بعد ما فهمنا الأساسيات، بدأنا نطبق بشكل عملي على موقعنا. خليني أشارككم بعض المشاكل اللي واجهتنا وكيف حليناها باستخدام ARIA.

المشكلة الأولى: الأزرار الغامضة

كان عنا في الموقع أزرار عبارة عن أيقونات فقط، بدون أي نص. مثلاً، أيقونة “الديسك” للحفظ. للمستخدم المبصر، الأيقونة واضحة. لكن لقارئ الشاشة، الوضع كان كارثي.

الكود قبل التعديل (السيء 👎):

<!-- المستخدم المبصر يرى أيقونة حفظ، لكن قارئ الشاشة لا يقرأ شيئًا مفيدًا -->
<span class="icon-save"></span>

لما يمر قارئ الشاشة على هذا العنصر، ممكن يقرأ “span” أو ما يقرأ أي شيءเลย. المستخدم ما عنده أي فكرة عن وظيفة هذا العنصر.

الكود بعد التعديل (الجيد 👍):

<!-- الآن قارئ الشاشة سيقرأ: "زر، حفظ التغييرات" -->
<span
  class="icon-save"
  role="button"
  tabindex="0"
  aria-label="حفظ التغييرات"
></span>

شو اللي عملناه؟

  • role="button": أخبرنا قارئ الشاشة أن هذا العنصر يتصرف كـ “زر”.
  • aria-label="حفظ التغييرات": أعطينا العنصر اسماً واضحاً ومفهوماً. هذا هو النص اللي رح يقرأه قارئ الشاشة.
  • tabindex="0": سمحنا للمستخدمين اللي بيستخدموا الكيبورد فقط بالوصول لهذا الزر عن طريق مفتاح Tab.

نصيحة أبو عمر: القاعدة الذهبية الأولى هي: إذا كان HTML يوفر عنصراً أصلياً للوظيفة، استخدمه! يعني بدل ما تعمل كل هاي القصة، كان الأفضل من البداية نستخدم عنصر <button>. هيك:
<button aria-label="حفظ التغييرات"><span class="icon-save"></span></button>
العناصر الأصلية بتيجي مع الوصولية مدمجة فيها “out of the box”. لا تعيد اختراع العجلة إلا إذا كنت مضطراً.

المشكلة الثانية: القوائم المنسدلة الصامتة

كان عنا قائمة منسدلة (Dropdown) مخصصة عملناها بـ JavaScript. الزر بيضغط عليه المستخدم، فتظهر قائمة. المشكلة إن قارئ الشاشة ما كان عنده أي فكرة عن العلاقة بين الزر والقائمة، ولا كان يعرف إذا القائمة مفتوحة أو مغلقة.

الكود بعد التعديل (باستخدام ARIA):

<!-- الزر الذي يفتح القائمة -->
<button
  id="user-menu-btn"
  aria-haspopup="true"
  aria-expanded="false"
  aria-controls="user-menu-list"
>
  قائمة المستخدم
</button>

<!-- القائمة نفسها، تكون مخفية في البداية -->
<ul
  id="user-menu-list"
  role="menu"
  aria-labelledby="user-menu-btn"
  style="display: none;"
>
  <li role="menuitem">ملفي الشخصي</li>
  <li role="menuitem">الإعدادات</li>
  <li role="menuitem">تسجيل الخروج</li>
</ul>

شرح السمات الجديدة:

  • aria-haspopup="true": تخبر قارئ الشاشة أن هذا الزر سيفتح نوعاً من القوائم المنبثقة.
  • aria-expanded="false": تخبر قارئ الشاشة أن القائمة حالياً “مغلقة”. طبعاً، لازم نغير هاي القيمة لـ "true" باستخدام JavaScript لما المستخدم يفتح القائمة.
  • aria-controls="user-menu-list": تربط الزر بالقائمة التي يتحكم بها. هذا مهم جداً عشان قارئ الشاشة يعرف شو اللي انفتح بالضبط.
  • في القائمة نفسها، role="menu" و role="menuitem" تعطي بنية دلالية واضحة.

المشكلة الثالثة: التنبيهات الديناميكية الخفية

لما المستخدم كان يحفظ نموذج معين، كانت تظهر رسالة صغيرة فوق تقول “تم الحفظ بنجاح”. هاي الرسالة بتظهر وبتختفي بعد ثانيتين. المشكلة؟ بتظهر وبتختفي بدون ما يحس عليها مستخدم قارئ الشاشة.

الحل كان باستخدام ما يسمى بـ “Live Regions”.

<!-- ضع هذا العنصر في مكان ما في صفحتك -->
<div id="status-message" role="status" aria-live="polite"></div>

كيف بتشتغل؟

السمة aria-live="polite" بتحول هذا الـ <div> لمنطقة “حية”. أي تغيير بيصير على المحتوى داخل هذا العنصر، قارئ الشاشة بيعلن عنه للمستخدم. كلمة "polite" (مهذب) بتعني إن قارئ الشاشة رح ينتظر حتى ينهي المستخدم ما يفعله حالياً، ثم يقرأ التنبيه الجديد. أما aria-live="assertive" (حازم) فهي تقاطع المستخدم فوراً وتقرأ التنبيه، ويجب استخدامها فقط للرسائل الهامة جداً (مثل رسائل الخطأ الفادح).

فالآن، كل ما علينا فعله هو إضافة نص الرسالة إلى هذا الـ div باستخدام JavaScript، وقارئ الشاشة سيتكفل بالباقي.

ما بعد ARIA: ثقافة الوصولية في الفريق

إصلاح هذه المشاكل كان مجرد بداية. الأهم كان تغيير ثقافة العمل في الفريق. الوصولية بطلت مجرد “مهمة” بنضيفها في آخر المشروع، بل صارت جزء من كل مرحلة:

  1. التصميم: المصمم صار يفكر في تباين الألوان (Color Contrast) ووضوح النصوص.
  2. البرمجة: المبرمجون صاروا يسألوا: “كيف رح يتعامل قارئ الشاشة مع هذا العنصر؟” وصار استخدام HTML الدلالي (Semantic HTML) هو الأساس.
  3. الاختبار (QA): بالإضافة للاختبارات المعتادة، صرنا نستخدم أدوات مثل WAVE و Axe، والأهم، صرنا نحاول نستخدم الموقع باستخدام الكيبورد فقط، أو حتى بتشغيل قارئ الشاشة (VoiceOver على ماك و NVDA على ويندوز) عشان نعيش التجربة بأنفسنا.

السؤال في اجتماعاتنا تحول من “هل الموقع شغال؟” إلى “هل الموقع شغال للجميع؟”.

الخلاصة: من موقع “أخرس” إلى تجربة للجميع

رحلتنا مع خالد علمتنا درس مهم: الإنترنت للجميع. الوصولية مش ميزة إضافية أو رفاهية، هي حق أساسي من حقوق المستخدم. هي جزء لا يتجزأ من بناء منتج احترافي ومحترم.

سمات ARIA قد تبدو معقدة في البداية، لكنها في الحقيقة جسر قوي بنبنيه بين واجهاتنا المعقدة وبين المستخدمين اللي بيعتمدوا على التقنيات المساعدة. ابدأ بالأساسيات: استخدم aria-label للأيقونات، تأكد من أن كل شيء يمكن الوصول إليه بالكيبورد، واستخدم HTML الأصلي كلما أمكن.

في النهاية، لما تبني منتجاً رقمياً، أنت لا تكتب كوداً فقط، بل تصنع تجربة. فاحرص على أن تكون هذه التجربة غنية ومتاحة للجميع بدون استثناء. بعد التعديلات، تواصلت مع خالد مرة أخرى، وكانت فرحته لا توصف وهو قادر على “رؤية” موقعنا من خلال “صوته” الجديد. هذه اللحظة كانت تساوي كل سطر كود كتبناه. يلا، ورجوني همتكم في جعل الويب مكاناً أفضل للجميع! 💪

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

تسويق رقمي

ميزانيتنا التسويقية كانت ثقباً أسود: كيف أنقذنا ‘نموذج الإحالة المبني على البيانات’ من جحيم إهدار المال؟

كنّا نحرق ميزانية التسويق بدون معرفة ما ينجح وما يفشل، حتى اكتشفنا "نموذج الإحالة المبني على البيانات". في هذه المقالة، أسرد لكم قصتنا وكيف حوّلنا...

2 مايو، 2026 قراءة المزيد
الشبكات والـ APIs

كانت نقرة المستخدم المزدوجة تكلفنا آلاف الدولارات: كيف أنقذتنا مفاتيح ‘Idempotency’ من جحيم الطلبات المكررة؟

في عالم تطوير البرمجيات، قد تتحول نقرة زر بريئة إلى كابوس مالي. أسرد لكم قصتي مع الطلبات المكررة التي كلفتنا الكثير، وكيف كان مفهوم بسيط...

2 مايو، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

قاعدة بياناتنا كانت تنهار: كيف أنقذنا التخزين المؤقت (Caching) من جحيم الاستعلامات المتكررة؟

كانت ليلة خميس، وكنا على وشك إغلاق أسبوع عمل مرهق، حين بدأت هواتفنا تضيء كشجرة عيد الميلاد. في هذه المقالة، أسرد لكم قصة حقيقية عن...

1 مايو، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

كانت بنيتنا التحتية قصرًا من ورق: كيف أنقذنا Terraform من جحيم الإعداد اليدوي؟

أشارككم تجربتي كـ "أبو عمر"، مبرمج فلسطيني، مع الفوضى التي تسببها إدارة السيرفرات اليدوية. سنكتشف معًا كيف حولت أداة Terraform بنيتنا التحتية من قصر ورقي...

1 مايو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

كان أفضل مهندسينا يرحلون: كيف أنقذ “سلم المسار الوظيفي” شركتنا من جحيم الركود؟

أشارككم قصة حقيقية عن كيفية مواجهتنا لمشكلة "نزيف العقول" في فريقنا الهندسي. نستعرض بالتفصيل كيف قمنا ببناء "سلم مسار وظيفي" (Career Ladder) واضح وشفاف أنقذنا...

1 مايو، 2026 قراءة المزيد
البودكاست