يتيح التنقّل بالتركيز الاتجاهي (باستخدام مفاتيح الأسهم أو لوحات التحكم) لمستخدمي لوحة المفاتيح فقط ومستخدمي الإدخال البديل التنقّل بين العناصر التفاعلية استنادًا إلى تنسيقها المرئي الثنائي الأبعاد. وهي مفيدة جدًا لواجهات المستخدم المكانية (مثل أشرطة الوسائط أو لوحات البيانات أو الكتالوجات المُدمجة)، ولكن يجب تنفيذها بعناية لتجنُّب تعطيل سلوكيات المتصفّح الأصلية، مثل الانتقال في إطار العرض.
يتناول هذا الدليل كيفية إنشاء عناصر واجهة مستخدم مركّبة تتيح التنقّل الاتجاهي الثنائي الأبعاد بشكل فعّال وسهل الاستخدام.
المبادئ الأساسية للبنية
عند تنفيذ التركيز المكاني المخصّص باستخدام مفاتيح الأسهم، يجب الالتزام بالقواعد الأساسية التالية:
- التقييد على التطبيقات المصغّرة المركّبة: لا تلغِ مفاتيح الأسهم في تدفق نص المستند العادي أو تنسيقات القائمة العمودية البسيطة حيث يُتوقع التنقل التلقائي المتسلسل باستخدام مفتاح Tab. يُرجى الاطّلاع على إرشادات الترميز المتعلّقة بأدوات تسهيل الاستخدام للحصول على إرشادات عامة حول تدفق المستندات.
- الحفاظ على التمرير الأصلي للحدود: في حال عدم توفّر عنصر يمكن التركيز عليه في الاتجاه الذي تم الضغط عليه، لا تمنع سلوك المتصفّح التلقائي. السماح للحدث بالانتشار حتى يتمكّن المتصفّح من الانتقال إلى نافذة العرض بشكلٍ أصلي يؤدي إلغاء مفاتيح الأسهم إلى تعطيل أدوات تسهيل الاستخدام بشكل غير مشروط (WCAG 1.4.10).
- التأكّد من ظهور التركيز ومحاذاته: عند تغيير التركيز، تأكَّد من أنّ العنصر الذي تم التركيز عليه حديثًا يظهر على الشاشة (مثلاً، باستخدام
scrollIntoView({ block: 'nearest', inline: 'nearest' })) ليبقى مرئيًا بالكامل. - التنسيق مع نظام التخطيط: يمكنك تحديد مواضع العناصر المرشّحة للتركيز من الأشكال الهندسية المحيطة المباشرة (
getBoundingClientRect()) أثناء معالجة كل ضغطة مفتاح. تجنَّب افتراض أنّ ترتيب DOM أو بنية الشبكة الثابتة يمثّلان التصميم البصري. يُرجى الاطّلاع على تنسيقات CSS والتصميم السريع الاستجابة للحصول على اقتراحات بشأن التنسيقات الحديثة.
إدارة التركيز لتسهيل الاستخدام
يجب أن تعرض الحاوية المكانية علامة تبويب واحدة للتنقّل المتسلسل في علامات تبويب الصفحة. داخل التطبيق المصغّر، يمكنك إدارة تركيز لوحة المفاتيح باستخدام نمط Roving Tabindex:
- يحتوي العنصر النشط على
tabindex="0". - تحتوي جميع العناصر غير النشطة على
tabindex="-1". - عند التنقّل، يمكنك نقل التركيز آليًا من خلال تغيير السمة
tabindex="0"واستدعاءfocus().
اختيار المرشحين المرئيين
في التنسيقات غير المتماثلة أو الملتفّة أو الشبكية، يتعذّر الربط المستند إلى الفهرس. بدلاً من ذلك، يمكنك استخلاص المرشحين من الهندسة المرئية المباشرة للضغط على المفتاح الحالي:
- Candidates: استخدِم العناصر الفرعية القابلة للتركيز في حاوية التطبيق المصغّر التي تجتاز
checkVisibility(). يمكن أن تحتوي العناصر المخفية على مستطيل بحجم صفر في(0, 0)ويجب ألا تصبح أهدافًا غير مقصودة لـupأوleft. - الهندسة: قراءة
getBoundingClientRect()للعنصر الذي تم التركيز عليه وكل عنصر مرشح أثناء التعامل مع الضغط على المفتاح. لا تخزِّن هذه المستطيلات مؤقتًا على مستوى التطبيق: يمكن أن يتغيّر التنسيق لأسباب عديدة، وقراءة عدد صغير من الأشكال الهندسية لا تستهلك الكثير من الموارد عند معالجة حدث رئيسي يحدّده المستخدم. - فلتر الاتجاه: يكون العنصر المرشّح في الاتجاه الذي تم الضغط عليه فقط عندما تكون حافته القريبة عند الحافة البعيدة للعنصر الحالي على هذا المحور أو أبعد منها، ما يسمح بتفاوت بسيط في التقريب إلى أقرب بكسل فرعي. على سبيل المثال، يجب أن يكون لدى المرشح لـ
rightcandidate.left >= current.right - tolerance. لا تقارن بين المراكز لتحديد ما إذا كان المرشح في الاتجاه. - العناصر المرشّحة المتوافقة أولاً: من بين العناصر المرشّحة التي تجتاز فلتر الاتجاه، يتم تفضيل العناصر التي يتداخل نطاقها على المحور العمودي مع نطاق العنصر الحالي. اختَر أصغر فجوة على محور التنقّل، مع كسر الروابط بأصغر إزاحة مركزية عمودية. يؤدي ذلك إلى إبقاء التنقّل في الصف أو العمود المرئي المجاور حتى عندما يكون العنصر عريضًا بشكل غير عادي.
- التقييم الاحتياطي: إذا لم يتداخل أي مرشح على المحور العمودي، يتم تقييم المرشحين المتبقين على أنّهم
gap + w * perpendicularCentreOffsetواختيار الحد الأدنى. استخدِم الوزنw >= 2كنقطة بداية، ثم اضبطه للتنسيق. يفضّل الوزن الأكبر المرشحين الأكثر توافقًا. - ما مِن مرشّح: لا يتم عرض أي نتائج. يجب ألا يستدعي معالج الأحداث
preventDefault()، ما يسمح للمتصفّح بالتمرير بشكل طبيعي.
قد يختلف التنفيذ الدقيق، ولكن يجب أن يكون اختبار الاتجاه مستندًا إلى الحواف وأن يتم تطبيق تفضيل التداخل قبل الإجراء الاحتياطي المرجّح. هذا هو جوهر الخوارزمية، لذا تجنَّب تقديم ذاكرة تخزين مؤقت أو وزن ثابت على أنّهما صحيحان بشكل عام.
الدمج مع ضغطات المفاتيح والتعاون في التمرير
يجب أن يمنع موجّه الأحداث الانتقال العادي في إطار العرض فقط عند حدوث انتقال صالح للتركيز المكاني:
- لا تعترض الحدث عند الضغط مع الاستمرار على مفتاح تعديل، أو عندما تكون قيمة
e.defaultPreventedصحيحة، أو عندما يستهلك هدف الحدث الأعمق مفاتيح الأسهم نفسها. استخدِمe.composedPath()[0]بدلاً منe.targetفقط، لأنّه يمكن إعادة توجيهe.targetإلى مضيف مخفي. يتم إجراء فحص عملي قابل للتعديل/التحكّم فيtarget.matches(':read-write, select, input[type="range"], [role="slider"]')، ولا يمكن فحص جذور الظل المغلقة. - يجب تحديد نطاق المستمع إلى حاوية التطبيق المصغّر، لكي تتعايش تطبيقات مصغّرة مكانية متعددة على صفحة واحدة.
- لا يتم اتخاذ أي إجراء إلا عندما يكون العنصر محلّ التركيز هو نفسه عنصرًا مرشحًا. إذا كانت العناصر تحتوي على عناصر تحكّم قابلة للتركيز، يمكنك جعل عناصر التحكّم هذه مرشّحة أيضًا أو تركها بمفردها، ولا تحلّ عنصرًا رئيسيًا باستخدام
closest(). - عند العثور على مرشّح، يمكنك استدعاء
preventDefault()وتعديلtabindexالمتغيّر واستدعاءfocus()واستخدامscrollIntoView({ block: 'nearest', inline: 'nearest' }). - في حال عدم العثور على أي مرشّح، يتم عرض النتيجة بدون استدعاء
preventDefault()لكي يستمر التمرير الأصلي.
تجنَّب إضافة اختصارات مكوّنة من حرف واحد، مثل h/j/k/l أو W/A/S/D للتنقّل المكاني. مفاتيح الأسهم ليست مفاتيح أحرف، ويؤدي الحفاظ على الانتقال الأصلي في حال عدم توفّر أي مرشّح إلى تجنُّب حظر حركة إطار العرض بدون داعٍ.