إنتقل إلى المحتوى الرئيسي

إمكانية الوصول إلى الويب (a11y) في Cursor: WCAG و ARIA و axe-core

إمكانية الوصول إلى الويب في Cursor

تضمن إمكانية الوصول إلى الويب (a11y) أن يتمكن الجميع، بما في ذلك الأشخاص ذوو الإعاقة، من إدراك وفهم والتفاعل مع تطبيقك. يُسرّع Cursor، وهو محرر IDE مدعوم بالذكاء الاصطناعي، التطوير الميسور من خلال توليد ترميز متوافق مع ARIA، وتشغيل تدقيقات آلية، وتطبيق إصلاحات WCAG عبر قاعدة التعليمات البرمجية الخاصة بك. يغطي هذا الدليل تسميات ARIA والامتثال لـ WCAG واختبارات axe-core وإصلاحات a11y بمساعدة الذكاء الاصطناعي واختبار قارئ الشاشة.

المتطلبات الأساسية​

قبل البدء، تأكد من توفر ما يلي:

  • Cursor (يُنصح بأحدث إصدار) كمحرر IDE الخاص بك
  • مشروع ويب (React أو Vue أو HTML و JavaScript بسيط)
  • Node.js 18 أو أعلى لأدوات الاختبار
  • معرفة أساسية بدلالات HTML
تلميح

إمكانية الوصول أرخص بكثير في البناء منذ البداية من إعادة التجهيز لاحقًا. افتح مشروعك في Cursor منذ البداية ودع الذكاء الاصطناعي يدقق المكونات أثناء كتابتها. إصلاح تسمية مفقودة أثناء التطوير يستغرق ثواني؛ إصلاح نفس المشكلة عبر تطبيق في الإنتاج يستغرق أسابيع.

فهم الامتثال لـ WCAG​

تعرّف إرشادات إمكانية الوصول إلى محتوى الويب (WCAG) كيفية جعل محتوى الويب يمكن الوصول إليه. وهي منظمة حول أربعة مبادئ، تُسمى غالبًا POUR:

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

تعرّف WCAG ثلاثة مستويات للامتثال: A (الحد الأدنى)، و AA (الهدف القانوني لمعظم المنظمات)، و AAA (مُعزز). اطلب من Cursor تلخيص متطلبات المستوى AA لميزة محددة:

اسرد معايير نجاح WCAG 2.2 المستوى AA التي تنطبق على نموذج
دفع متعدد الخطوات مع منتقيات التواريخ وحقول بطاقة الائتمان.

يُرجع Cursor المعايير ذات الصلة ويشرح كيفية تلبية كل واحد منها باقتراحات كود ملموسة.

أساسيات HTML الدلالي​

HTML الدلالي هو أساس إمكانية الوصول. العنصر الصحيح غالبًا ما يلغي الحاجة إلى ARIA تمامًا. يساعدك Cursor في اختيار وتوليد الترميز الصحيح.

توليد مكونات دلالية​

اطلب من Cursor بناء شريط تنقل مع إمكانية الوصول المدمجة:

أنشئ تنقل موقع متجاوب في React يقوم بـ:
- استخدام معلم <nav> مع اسم يمكن الوصول إليه
- امتلاك رابط تخطي في أعلى الصفحة
- تبديل قائمة الجوال مع aria-expanded و aria-controls
- الإغلاق عند Escape وإرجاع التركيز إلى زر التبديل
- دعم التنقل الكامل بلوحة المفاتيح

يُنشئ Cursor المكون:

import { useState, useRef, useEffect } from 'react';

export function SiteNav({ links }: { links: { href: string; label: string }[] }) {
const [open, setOpen] = useState(false);
const toggleRef = useRef<HTMLButtonElement>(null);

useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
setOpen(false);
toggleRef.current?.focus();
}
};
document.addEventListener('keydown', onKey);
return () => document.removeEventListener('keydown', onKey);
}, [open]);

return (
<>
<a href="#main" className="skip-link">Skip to main content</a>
<nav aria-label="Main navigation">
<button
ref={toggleRef}
aria-expanded={open}
aria-controls="mobile-menu"
onClick={() => setOpen((v) => !v)}
>
Menu
</button>
<ul id="mobile-menu" hidden={!open}>
{links.map((link) => (
<li key={link.href}>
<a href={link.href}>{link.label}</a>
</li>
))}
</ul>
</nav>
</>
);
}
تلميح

القاعدة الأولى لـ ARIA هي: لا تستخدم ARIA إذا كان عنصر HTML أصلي موجود. زر <button> حقيقي يمنحك تركيز لوحة المفاتيح وتنشيط Enter و Space ودلالات قارئ الشاشة مجانًا. اطلب من Cursor: "استبدل زر div-based هذا بزر دلالي،" عندما ترى onClick على عنصر غير تفاعلي.

تسميات وأدوار ARIA​

عندما لا يستطيع HTML الأصلي التعبير عن الدلالات التي تحتاجها، يملأ ARIA الفجوة. يُنشئ Cursor سمات ARIA الصحيحة ويحذر من الأخطاء الشائعة.

نماذج يمكن الوصول إليها​

حقول النموذج تحتاج إلى تسميات. اطلب من Cursor إنشاء حقل نموذج يمكن الوصول إليه:

أنشئ مكوّن FormField قابل لإعادة الاستخدام مع:
- <label> مرتبط باستخدام htmlFor
- سمة aria-required عندما تكون مطلوبة
- رابط aria-describedby لنص المساعدة والخطأ
- رسائل خطأ مع role="alert"
import { useId } from 'react';

interface FormFieldProps {
label: string;
name: string;
type?: string;
required?: boolean;
error?: string;
helper?: string;
}

export function FormField({ label, name, type = 'text', required, error, helper }: FormFieldProps) {
const fieldId = useId();
const helperId = `${fieldId}-helper`;
const errorId = `${fieldId}-error`;
const describedBy = [helper && helperId, error && errorId].filter(Boolean).join(' ') || undefined;

return (
<div>
<label htmlFor={fieldId}>
{label}
{required && <span aria-hidden="true">*</span>}
</label>
<input
id={fieldId}
name={name}
type={type}
required={required}
aria-required={required}
aria-describedby={describedBy}
aria-invalid={!!error}
/>
{helper && !error && (
<p id={helperId} className="helper-text">{helper}</p>
)}
{error && (
<p id={errorId} role="alert" className="error-text">{error}</p>
)}
</div>
);
}

المناطق الحية للتحديثات الديناميكية​

عندما يُحدّث المحتوى ديناميكيًا (إشعارات، نتائج البحث)، تحتاج قارئات الشاشة إلى منطقة حية للإعلان عن التغييرات. يُنشئ Cursor النمط:

export function SearchResults({ query, results }: { query: string; results: string[] }) {
return (
<div
aria-live="polite"
aria-atomic="true"
role="status"
>
{results.length === 0 ? (
<p>No results for "{query}".</p>
) : (
<p>{results.length} results found for "{query}".</p>
)}
<ul>
{results.map((r) => <li key={r}>{r}</li>)}
</ul>
</div>
);
}
warning

استخدم aria-live="polite" للتحديثات غير العاجلة و aria-live="assertive" فقط للتنبيهات الحرجة. الإفراط في استخدام المناطق الحية الحازمة يُقاطع مستخدمي قارئ الشاشة باستمرار ويجعل تطبيقك غير قابل للاستخدام. لا تستخدم أبدًا role="alert" لرسائل النجاح؛ احجزها للأخطاء الفعلية التي تحتاج إلى اهتمام فوري.

اختبارات axe-core الآلية​

تكتشف الأدوات الآلية حوالي 30 إلى 40 بالمائة من مشاكل إمكانية الوصول. axe-core هو معيار الصناعة. يمكن لـ Cursor دمجه في مجموعة الاختبارات الخاصة بك وخط أنابيب CI.

إعداد axe-core مع Jest​

اطلب من Cursor إضافة اختبارات إمكانية وصول آلية:

أضف axe-core إلى مشروع React الخاص بي. أنشئ اختبار Jest
يعرض مكوّن SiteNav باستخدام Testing Library ويشغل قواعد axe.

يثبّت Cursor التبعيات ويكتب الاختبار:

npm install -D @axe-core/react axe-core jest-axe @testing-library/react @testing-library/jest-dom
// src/components/SiteNav.test.tsx
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
import { SiteNav } from './SiteNav';

expect.extend(toHaveNoViolations);

const links = [
{ href: '/', label: 'Home' },
{ href: '/about', label: 'About' },
];

describe('SiteNav', () => {
it('has no accessibility violations when closed', async () => {
const { container } = render(<SiteNav links={links} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});

it('has no accessibility violations when open', async () => {
const { container, getByText } = render(<SiteNav links={links} />);
getByText('Menu').click();
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});

مساعد اختبار axe قابل لإعادة الاستخدام​

يمكن لـ Cursor إنشاء مساعد قابل لإعادة الاستخدام بحيث يبقى كل اختبار مكون متسقًا:

import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';

expect.extend(toHaveNoViolations);

export async function expectAccessible(component: React.ReactElement) {
const { container } = render(component);
const results = await axe(container, {
rules: {
// تعطيل القواعد التي تعالجها عن قصد في مكان آخر
region: { enabled: false },
},
});
expect(results).toHaveNoViolations();
return results;
}

استخدمه في كل اختبار مكون:

import { expectAccessible } from '../test/expectAccessible';
import { FormField } from './FormField';

it('is accessible', async () => {
await expectAccessible(<FormField label="Email" name="email" required />);
});
تلميح

شغّل مجموعة axe الكاملة قبل كل التزام مع نص حزمة. اطلب من Cursor: "أضف نص a11y إلى package.json يشغل جميع اختبارات axe ويفشل عند المخالفات." هذا يمنع الانحدارات من الوصول إلى فرعك الرئيسي.

إصلاحات إمكانية الوصول بمساعدة الذكاء الاصطناعي​

يمكن لذكاء Cursor الاصطناعي مسح ملف مكون كامل، والعثور على مشاكل إمكانية الوصول، وتطبيق الإصلاحات في تمريرة واحدة. هذا أحد أهم تدفقات عمل a11y.

تدقيق مكون​

افتح مكونًا في Cursor وشغّل هذا الطلب في محادثة الذكاء الاصطناعي:

دقق هذا المكوّن للامتثال لـ WCAG 2.2 AA. اذكر كل مشكلة
مع رقم السطر، اشرح لماذا تفشل، وأعد كتابة الكود مع
الإصلاحات. أضف تعليقات تشرح كل تغيير.

قد يُبلغ Cursor عن:

  • السطر 12: <div onClick> غير قابل للوصول بلوحة المفاتيح. استبدل بـ <button>.
  • السطر 20: <img> ليس له سمة alt. أضف نص بديل وصفي.
  • السطر 28: تباين اللون هو 3.1:1، أقل من الحد الأدنى 4.5:1 للنص العادي.
  • السطر 35: حوار مشروط لا يحتوي على فخ تركيز. يمكن للمستخدمين Tab خلف الحوار.

ثم يطبق Cursor الإصلاحات:

// قبل
<div className="card" onClick={openDetails}>
<img src={product.image} />
<h3 style={{ color: '#999' }}>{product.name}</h3>
</div>

// بعد
<button
className="card"
onClick={openDetails}
aria-label={`View details for ${product.name}`}
>
<img src={product.image} alt={`${product.name} product photo`} />
<h3 style={{ color: '#595959' }}>{product.name}</h3>
</button>

توليد فخ التركيز​

تحتاج النوافذ المشروطة والحواريات إلى فخ تركيز حتى لا يتمكن مستخدمو لوحة المفاتيح من الهروب من الحوار باستخدام Tab. اطلب من Cursor:

أضف فخ تركيز إلى مكوّن الحوار هذا. انقل التركيز إلى أول
عنصر قابل للتركيز عند الفتح، أمسك Tab و Shift+Tab داخل
الحوار، وأعد التركيز إلى زر التشغيل عند الإغلاق.
import { useEffect, useRef } from 'react';

const FOCUSABLE = 'a[href], button:not([disabled]), input, textarea, select, [tabindex]:not([tabindex="-1"])';

export function useFocusTrap(active: boolean) {
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (!active || !containerRef.current) return;
const container = containerRef.current;
const elements = container.querySelectorAll<HTMLElement>(FOCUSABLE);
if (elements.length === 0) return;

const first = elements[0];
const last = elements[elements.length - 1];
first.focus();

const onKey = (e: KeyboardEvent) => {
if (e.key !== 'Tab') return;
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
};

container.addEventListener('keydown', onKey);
return () => container.removeEventListener('keydown', onKey);
}, [active]);

return containerRef;
}
warning

فخ التركيز بلا معنى إذا لم يكن HTML الأساسي قابلاً للوصول بلوحة المفاتيح. الفخ يدير فقط العناصر القابلة للتركيز فعليًا. إذا كان حوارك يحتوي فقط على عناصر <div> مع معالجات onClick، فلا يوجد شيء للتركيز عليه في فخ التركيز. اقرن الفخ دائمًا بعناصر دلالية قابلة للتركيز.

اختبار قارئ الشاشة​

تكتشف الاختبارات الآلية المشاكل الهيكلية، لكن الاختبار اليدوي فقط مع قارئ شاشة يكشف التجربة المعاشة. يمكن لـ Cursor إنشاء نصوص اختبار وقوائم مرجعية.

قائمة مرجعية للاختبار بلوحة المفاتيح فقط​

اطلب من Cursor إنشاء قائمة مرجعية للاختبار بلوحة المفاتيح:

أنشئ قائمة مرجعية للاختبار بلوحة المفاتيح فقط لتطبيق ويب
يغطي التنقل والنماذج وعناصر الواجهة والمحتوى الديناميكي.

يُنتج Cursor:

  1. تنقل عبر الصفحة بـ Tab بترتيب منطقي دون أفخاخ.
  2. رابط التخطي هو أول عنصر قابل للتركيز ويقفز إلى المحتوى الرئيسي.
  3. جميع العناصر التفاعلية يمكن الوصول إليها بـ Tab و Shift+Tab.
  4. عناصر الواجهة المخصصة (علامات تبويب، أكورديون) تدعم مفاتيح الأسهم و Home/End.
  5. النوافذ المشروطة تُمسك التركيز وتُعيده إلى المشغل عند الإغلاق.
  6. مؤشر التركيز المرئي موجود على كل عنصر قابل للتركيز.
  7. Enter و Space ينشطان الأزرار؛ Enter ينشط الروابط.
  8. النماذج تُرسل بـ Enter على زر الإرسال.

الاختبار مع NVDA و JAWS و VoiceOver​

يمكن لـ Cursor إنشاء ملاحظات اختبار لكل قارئ شاشة:

اكتب دليل بدء سريع لاختبار تطبيقي مع NVDA على Windows
و VoiceOver على macOS و TalkBack على Android. ضمّن اختصار
بدء كل قارئ وكيفية التنقل حسب العنوان والمعلم.

يُرجع Cursor جدول مقارنة ودليل تنقل يمكنك حفظه كملف مرجعي في مشروعك.

تباين الألوان والتصميم البصري​

الوصول البصري جزء من صورة WCAG. التباين المنخفض هو أحد أكثر الإخفاقات شيوعًا.

التحقق من التباين بالذكاء الاصطناعي​

اطلب من Cursor تقييم رموز التصميم الخاصة بك:

إليك رموز الألوان الخاصة بي في tailwind.config.js. تحقق
من كل زوج نص وخلفية مقابل نسب تباين WCAG AA (4.5:1
للنص العادي، 3:1 للنص الكبير). ضع علامة على أي إخفاقات
واقترح إصلاحات.

يقرأ Cursor التكوين، ويحسب نسب التباين، ويُبلغ عن الإخفاقات:

// رموز tailwind.config.js التي تفشل AA
// text-gray-400 on bg-white: 2.85:1 — فشل
// إصلاح: استخدم text-gray-600 (#4B5563) لـ 7.21:1

يُحدّث Cursor التكوين:

module.exports = {
theme: {
extend: {
colors: {
'text-secondary': '#4B5563', // كان #9CA3AF، الآن يجتاز AA
},
},
},
};
تلميح

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

إمكانية الوصول في CI​

تنتمي فحوصات a11y الآلية إلى خط أنابيب التكامل المستمر الخاص بك. يمكن لـ Cursor إنشاء التكوين.

Lighthouse CI مع فئة a11y​

اطلب من Cursor إضافة Lighthouse CI:

أضف Lighthouse CI إلى سير عمل GitHub Actions الخاص بي مع
فئة إمكانية الوصول الممكّنة وحد أدنى للنقاط 0.9.
# .github/workflows/lighthouse.yml
name: Lighthouse
on: [pull_request]

jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npm run build
- name: Run Lighthouse
uses: treosh/lighthouse-ci-action@v11
with:
urls: |
http://localhost:3000
uploadArtifacts: true
configPath: .lighthouserc.json
// .lighthouserc.json
{
"ci": {
"assert": {
"assertions": {
"categories:accessibility": ["error", { "minScore": 0.9 }]
}
},
"collect": {
"startServerCommand": "npm run start",
"startServerReadyPattern": "ready",
"numberOfRuns": 3
}
}
}

ملخص أفضل الممارسات​

ضع هذه المبادئ في الاعتبار عند بناء تطبيقات يمكن الوصول إليها في Cursor:

  • افضل HTML الدلالي على ARIA كلما كان عنصر أصلي مناسبًا.
  • سمّل كل إدخال بـ <label> حقيقي أو aria-label.
  • اجعل كل شيء قابل للتشغيل بلوحة المفاتيح؛ الفأرة اختياري.
  • أتمت باستخدام axe-core في كل اختبار مكون.
  • اختبر يدويًا بقارئ شاشة واحد على الأقل.
  • حافظ على تباين 4.5:1 للنص العادي ومؤشرات تركيز مرئية.
  • شغّل فحوصات a11y في CI حتى لا تُشحن الانحدارات أبدًا.

من خلال الجمع بين معرفة WCAG والتدقيق وتوليد الكود المدعوم بالذكاء الاصطناعي في Cursor، يمكنك بناء واجهات شاملة تعمل للجميع. دع Cursor ينشئ الترميز والاختبارات الميسورة، ثم تحقق من النتائج بقارئات شاشة حقيقية قبل الشحن.