تطوير الويب 3 دقيقة للقراءة 742 مشاهدات

بناء تطبيقات ويب يمكن الوصول إليها: دليل المطور الشامل لمعايير WCAG 2.2

أنشئ تجارب ويب شاملة تعمل للجميع. يغطي هذا الدليل إرشادات WCAG 2.2 وأدوات الاختبار وأنماط التطبيق العملية.

Accessibility and inclusive design

بناء تطبيقات ويب يمكن الوصول إليها ليس مجرد امتثال — بل هو إنشاء تجارب تعمل للجميع. ومع كون WCAG 2.2 الآن المعيار، يغطّي هذا الدليل استراتيجيات تطبيق عملية للمطوّرين.

فهم WCAG 2.2

تُنظَّم WCAG 2.2 حول أربعة مبادئ (POUR):

  1. قابل للإدراك (Perceivable): يجب تقديم المعلومات بطرق يمكن للمستخدمين إدراكها
  2. قابل للتشغيل (Operable): يجب أن تكون مكوّنات الواجهة قابلة للتشغيل من جميع المستخدمين
  3. مفهوم (Understandable): يجب أن تكون المعلومات والتشغيل مفهومة
  4. متين (Robust): يجب أن يكون المحتوى متيناً بما يكفي للتقنيات المساعِدة

أنماط أساسية لإمكانية الوصول

HTML الدلالي

<!-- Bad: div soup -->
<div class="header">
    <div class="nav">
        <div class="nav-item">Home</div>
    </div>
</div>

<!-- Good: semantic elements -->
<header>
    <nav aria-label="Main navigation">
        <ul>
            <li><a href="/">Home</a></li>
        </ul>
    </nav>
</header>

النماذج القابلة للوصول

<form>
    <div class="form-group">
        <label for="email">Email address</label>
        <input
            type="email"
            id="email"
            name="email"
            aria-describedby="email-help email-error"
            aria-invalid="true"
            required
        >
        <p id="email-help" class="help-text">
            We'll never share your email.
        </p>
        <p id="email-error" class="error" role="alert">
            Please enter a valid email address.
        </p>
    </div>

    <button type="submit">Subscribe</button>
</form>

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

// Custom dropdown with keyboard support
function Dropdown({ options, onChange }) {
    const [isOpen, setIsOpen] = useState(false);
    const [focusIndex, setFocusIndex] = useState(0);

    const handleKeyDown = (e) => {
        switch (e.key) {
            case 'ArrowDown':
                e.preventDefault();
                setFocusIndex(i => Math.min(i + 1, options.length - 1));
                break;
            case 'ArrowUp':
                e.preventDefault();
                setFocusIndex(i => Math.max(i - 1, 0));
                break;
            case 'Enter':
            case ' ':
                e.preventDefault();
                onChange(options[focusIndex]);
                setIsOpen(false);
                break;
            case 'Escape':
                setIsOpen(false);
                break;
        }
    };

    return (
        <div
            role="listbox"
            tabIndex={0}
            onKeyDown={handleKeyDown}
            aria-activedescendant={\`option-\${focusIndex}\`}
        >
            {options.map((option, i) => (
                <div
                    key={option.value}
                    id={\`option-\${i}\`}
                    role="option"
                    aria-selected={i === focusIndex}
                >
                    {option.label}
                </div>
            ))}
        </div>
    );
}

الألوان والتباين

تتطلّب WCAG 2.2:

  • النص العادي: نسبة تباين 4.5:1
  • النص الكبير (18pt+): نسبة تباين 3:1
  • مكوّنات الواجهة: 3:1 مقابل الألوان المجاورة
/* CSS custom properties for accessible colors */
:root {
    --text-primary: #1a1a1a;     /* 15:1 on white */
    --text-secondary: #595959;   /* 7:1 on white */
    --background: #ffffff;
    --accent: #0066cc;           /* 5.9:1 on white */
    --error: #d32f2f;            /* 4.8:1 on white */
}

أنماط ARIA

المناطق الحيّة (Live Regions)

<!-- Announce dynamic content changes -->
<div aria-live="polite" aria-atomic="true">
    {{ statusMessage }}
</div>

<!-- For urgent alerts -->
<div role="alert">
    Your session will expire in 2 minutes.
</div>

النوافذ الحوارية (Modal Dialogs)

<div
    role="dialog"
    aria-modal="true"
    aria-labelledby="dialog-title"
    aria-describedby="dialog-description"
>
    <h2 id="dialog-title">Confirm deletion</h2>
    <p id="dialog-description">
        This action cannot be undone.
    </p>
    <button onClick={onConfirm}>Delete</button>
    <button onClick={onCancel}>Cancel</button>
</div>

أدوات الاختبار

  • axe DevTools: امتداد متصفّح للاختبار الآلي
  • WAVE: أداة تقييم إمكانية الوصول للويب
  • Lighthouse: مدمج في Chrome DevTools
  • قارئات الشاشة: NVDA (ويندوز)، VoiceOver (ماك/iOS)
// Automated testing with jest-axe
import { axe, toHaveNoViolations } from 'jest-axe';

expect.extend(toHaveNoViolations);

test('form is accessible', async () => {
    const { container } = render(<ContactForm />);
    const results = await axe(container);
    expect(results).toHaveNoViolations();
});

إمكانية الوصول رحلة لا وجهة. ابدأ بالأساسيات، واختبر بانتظام، وحسّن باستمرار.

مشاركة هذه المقالة:
ES
كتبه

Edrees Salih

مهندس برمجيات متكامل يتمتع بخبرة 9 سنوات. شغوف ببناء حلول قابلة للتطوير ومشاركة المعرفة مع مجتمع المطورين.

عرض الملف الشخصي

التعليقات (0)

اترك تعليقًا

لن يتم نشر بريدك الإلكتروني.

لا توجد تعليقات بعد. كن أول من يشارك أفكاره!

مقالات ذات صلة

مقالات ذات صلة

هل تحتاج مساعدة في مشروعك؟

احجز استشارة مجانية لمدة 30 دقيقة لمناقشة تحدياتك التقنية واستكشاف الحلول معًا.