الوحدة 3 · لوحة المفاتيح والتركيز وARIA
الوصول بلوحة المفاتيح والتركيز المرئي
18 دقراءة 4 دبيئة تجريب الكود
الدرس في لمحة
اجعل كل عنصر تحكّم في Ticketly قابلًا للوصول بلوحة المفاتيح بترتيب منطقي، وأظهر مؤشّر تركيز واضحًا، وأضِف رابط تخطٍّ (skip link)، وامنع الأشرطة الثابتة من إخفاء التركيز.
- 1المفاتيح التي يستخدمها الناس
- 2ترتيب التركيز يتبع الـ DOM
- 3اجعل التركيز مرئيًا
- 4روابط التخطّي والأشرطة الثابتة
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
ضع الفأرة في الدرج وحاول شراء تذكرة الجمعة في Ticketly. ستكتشف ثلاثة أشياء في نحو ثلاثين ثانية. مفتاح Tab يمرّ بك على أربعين رابطًا ونيّف في الترويسة والتذييل قبل أن يصل إلى المهرجان. ثم يقفز التركيز من زر السبت إلى زر الجمعة ويعود إلى الأعلى. ومعظم الوقت لا ترى أين التركيز أصلًا، لأن أحدهم كتب outline: none عام 2019 ليتخلّص من «ذلك المربع الأزرق القبيح».
الوصول بلوحة المفاتيح ليس حالة نادرة. كل من يستخدم قارئ شاشة على حاسوب مكتبي يعتمد على لوحة المفاتيح، وكذلك مستخدمو أجهزة التبديل، والمصابون بالرعاش، ومن تعطّلت لوحة اللمس لديهم، والمطوّرون الذين يفضّلونها ببساطة. يشترط معيار WCAG 2.1.1 Keyboard (A) أن يعمل كل شيء من لوحة المفاتيح، ومعيار 2.1.2 (A) ألا يُحبس التركيز أبدًا.
المفاتيح التي يستخدمها الناس
- Tab / Shift+Tab: التنقّل بين العناصر التفاعلية (الروابط والأزرار وحقول النماذج).
- Enter: اتّباع رابط، أو تفعيل زر، أو إرسال نموذج.
- Space: تفعيل زر، أو تبديل مربّع اختيار، أو تمرير الصفحة حين لا يكون أي عنصر عليه التركيز.
- مفاتيح الأسهم: التنقّل داخل widget، مثل أزرار radio أو قائمة select أو التبويبات أو القوائم.
- Escape: إغلاق نافذة حوار أو قائمة أو نافذة منبثقة.
العناصر الأصلية تدعم كل هذا أصلًا. ومهمّتك في الغالب ألا تكسره، وأن تلتزم بهذه الأعراف حين تبني widgets مخصّصة في درس أنماط الـ Widgets.
ترتيب التركيز يتبع الـ DOM
ينتقل Tab بين العناصر القابلة للتركيز بترتيب المصدر. إن وضع التخطيط المرئي زر “Add Saturday” قبل “Add Friday” لكن الكود يضعهما بالعكس، فسيبدو التركيز كأنه يقفز إلى الخلف. والإصلاح أن تضع الكود بالترتيب الذي تريد أن يقابله الناس به. واحذر من CSS الذي يعيد ترتيب العناصر بصريًا، مثل order أو flex-direction: row-reverse أو التموضع الصريح في الـ grid، لأن التركيز سيظلّ يتبع الكود (2.4.3 Focus Order).
تضبط tabindex قابلية التركيز:
| القيمة | الأثر | استخدمها لـ |
|---|---|---|
0 |
قابل للتركيز، بترتيب الـ DOM | عنصر تحكّم مخصّص مبني من عنصر غير تفاعلي |
-1 |
قابل للتركيز من السكربت فقط، لا بمفتاح Tab | عناوين أو حاويات تنقل التركيز إليها |
1 أو أكثر |
يتقدّم على كل شيء آخر | لا تستخدمها أبدًا |
اجعل التركيز مرئيًا
مستخدم لوحة المفاتيح بلا مؤشّر تركيز مرئي كمستخدم الفأرة بمؤشّر غير مرئي. يشترط معيار WCAG 2.4.7 Focus Visible (AA) وجود مؤشّر؛ ويعني معيار 1.4.11 Non-text Contrast أن تباينه يجب ألا يقلّ عن 3:1 مع ما يحيط به.
الأداة الحديثة هي :focus-visible. تطبّقها المتصفّحات حين يجب أن يظهر التركيز: دائمًا عند التنقّل بلوحة المفاتيح وفي الحقول النصية، لكن عادةً لا حين يُنقر زر بالفأرة. هذا يجيب عن شكوى المصمّمة الحقيقية دون أن يؤذي أحدًا:
:focus-visible {
outline: 3px solid #5b3cc4;
outline-offset: 2px;
}استخدم outline لا box-shadow للحلقة. سمات التباين في Windows (وضع forced colors) تحذف الظلال لكنها تُبقي الـ outline، فالمؤشّر المبني على الظلّ وحده يختفي عند أكثر الناس حاجة إليه.
روابط التخطّي والأشرطة الثابتة
في ترويسة Ticketly شعار، وعشرة روابط قائمة، وحقل بحث، وقائمة للحساب: ثلاث عشرة محطة لمفتاح Tab. على مستخدم لوحة المفاتيح أن يمرّ عليها كلها بمفتاح Tab في كل صفحة. يطلب معيار WCAG 2.4.1 Bypass Blocks (A) طريقة لتجاوز المحتوى المتكرّر، والحلّ الكلاسيكي هو رابط التخطّي (skip link): أول عنصر قابل للتركيز في الصفحة، مخفي حتى يتلقّى التركيز.
<body>
<a class="skip-link" href="#main">Skip to main content</a>
<header>…</header>
<main id="main">…</main>
</body>.skip-link {
position: absolute;
inset-block-start: 8px;
inset-inline-start: 8px;
padding: 8px 12px;
background: #fff;
transform: translateY(-150%);
}
.skip-link:focus {
transform: none;
}لا تُخفِه بـ display: none، فهذا يُخرجه من ترتيب Tab. نقله خارج الشاشة وإعادته عند التركيز يُبقيه قابلًا للوصول ويُظهره تمامًا حين يحتاجه مستخدم لوحة المفاتيح.
الترويسات الثابتة وأشرطة ملفات تعريف الارتباط تجلب المشكلة المعاكسة: ينتقل التركيز إلى عنصر مخفي تحتها، وهذا يخالف معيار 2.4.11 Focus Not Obscured (AA). أخبر المتصفّح بمقدار ما تغطّيه الأجزاء الثابتة من الـ viewport، فيمرّر العناصر التي عليها التركيز بعيدًا عنها:
html {
scroll-padding-block-start: 96px; /* sticky header height plus a little air */
}أما شريط ملفات تعريف الارتباط، فالإصلاح الحقيقي ألا تتركه يطفو فوق المحتوى إلى ما لا نهاية: ضعه في تدفّق الصفحة، أو تأكّد أنه يمكن إغلاقه قبل الوصول إلى أي شيء آخر.
صار بالإمكان عبور Ticketly من أعلاه إلى أسفله بلوحة المفاتيح. يتناول الدرس التالي الحالات الأصعب، حيث يجب على كودك أن ينقل التركيز بنفسه: نوافذ الحوار والتنقّل في التطبيقات أحادية الصفحة.
أهم النقاط
- ترتيب التركيز يتبع ترتيب الـ DOM، فضع الكود بالترتيب الذي يجب أن يقابله الناس به، ولا تعاكسه بإعادة الترتيب عبر CSS.
- استخدم tabindex=“0” لإضافة عنصر تحكّم مخصّص إلى ترتيب Tab، وtabindex=“-1” للعناصر التي تنقل إليها التركيز من السكربت؛ ولا تستخدم أبدًا tabindex موجبًا.
- لا تحذف إطار التركيز أبدًا دون بديل؛ نسّق :focus-visible بمؤشّر لا يقلّ تباينه عن 3:1.
- رابط التخطّي كأول عنصر قابل للتركيز يتيح لمستخدمي لوحة المفاتيح تجاوز التنقّل المتكرّر، وscroll-padding يمنع الأشرطة الثابتة من إخفاء التركيز.