Web Accessibility: WCAG 2.1 AA Compliance Guide

Build WCAG 2.1 AA compliant web apps with this practical guide. Covers semantic HTML, ARIA, keyboard navigation, color contrast, screen readers, and automated testing tools.

E
ECOSIRE Research and Development Team
|19 مارچ، 202611 منٹ پڑھیں2.5k الفاظ|

ہماری Compliance & Regulation سیریز کا حصہ

مکمل گائیڈ پڑھیں

ویب تک رسائی: WCAG 2.1 AA تعمیل گائیڈ

رسائی ایک خصوصیت نہیں ہے جسے آپ لانچ کے بعد شامل کرتے ہیں — یہ ایک بنیادی معیار کا وصف ہے، جیسا کہ کارکردگی یا سیکیورٹی۔ WCAG 2.1 AA کی تعمیل اب قانونی طور پر EU (یورپی ایکسیسبیلٹی ایکٹ، جون 2025 سے نافذ)، US (ADA ٹائٹل III کیس قانون) اور بہت سے دوسرے دائرہ اختیار میں ضروری ہے۔ تعمیل کے علاوہ، قابل رسائی انٹرفیس بہتر طور پر تبدیل ہوتے ہیں، تلاش میں اعلیٰ درجہ دیتے ہیں، اور اندازے کے مطابق دنیا بھر میں 1.3 بلین معذور افراد کی خدمت کرتے ہیں۔

یہ گائیڈ ایک عملی نفاذ کا دستورالعمل ہے، چیک لسٹ نہیں۔ آپ WCAG کے چار اصول، سب سے زیادہ اثر انگیز تکنیک، منظم طریقے سے جانچ کرنے کا طریقہ، اور اپنے React/Next.js ترقیاتی ورک فلو میں رسائی کو کیسے ضم کرنا سیکھیں گے تاکہ یہ درست رہے۔

اہم ٹیک ویز

  • WCAG 2.1 AA کے لیے چاروں POUR اصولوں کی ضرورت ہے: قابل غور، قابل عمل، قابل فہم، مضبوط
  • سیمنٹک HTML کے ساتھ شروع کریں - یہ کسی بھی ARIA کو شامل کرنے سے پہلے 70% مفت رسائی فراہم کرتا ہے۔
  • کم سے کم رنگ کے تضاد کا تناسب: عام متن کے لیے 4.5:1، بڑے متن کے لیے 3:1 (18pt/14pt بولڈ)
  • ہر انٹرایکٹو عنصر کی بورڈ کو قابل توجہ فوکس اشارے کے ساتھ قابل توجہ ہونا چاہیے۔
  • اسکرین ریڈرز رسائی کے درخت کی بنیاد پر اعلان کرتے ہیں — NVDA (Windows) اور VoiceOver (Mac) کے ساتھ ٹیسٹ
  • ARIA ایک آخری حربہ ہے - یہ صرف اس بات کو تبدیل کرتا ہے کہ کس طرح معاون ٹیکنالوجیز DOM کی ترجمانی کرتی ہیں، سلوک کی نہیں۔
  • اپنی CI پائپ لائن میں axe-core کے ساتھ خودکار بنائیں۔ دستی جانچ اس بات کو پکڑتی ہے کہ آٹومیشن کیا کھو جاتا ہے۔
  • اپنے ایکسیسبیلٹی سٹیٹمنٹ کو دستاویز کریں اور صارفین کو مسائل کی اطلاع دینے کے لیے فیڈ بیک میکانزم فراہم کریں۔

چار اصول

WCAG 2.1 چار اصولوں کے ارد گرد ترتیب دیا گیا ہے۔ ہر کامیابی کا معیار ان میں سے کسی ایک سے تعلق رکھتا ہے۔

قابل ادراک: معلومات ان طریقوں سے پیش کی جانی چاہئیں جن کو صارفین سمجھ سکتے ہیں۔ اس میں تصاویر کے لیے متن کے متبادل، ویڈیو کے لیے کیپشن، کافی رنگ کے تضاد، اور ایسے مواد کا احاطہ کیا گیا ہے جو معنی کو ظاہر کرنے کے لیے صرف رنگ پر انحصار نہیں کرتا ہے۔

آپریبل: تمام فعالیتیں کی بورڈ کے ذریعے قابل عمل ہونی چاہئیں، جس میں بات چیت کرنے کے لیے کافی وقت ہو، کوئی ضبط کرنے والا مواد نہ ہو، اور نیویگیبل ڈھانچہ (لنک، صفحہ کے عنوانات، فوکس آرڈر کو چھوڑ دیں)۔

قابل فہم: مواد پڑھنے کے قابل اور پیش گوئی کے قابل ہونا چاہیے۔ زبان کی شناخت ہونی چاہیے، غلطی کے پیغامات وضاحتی ہونے چاہئیں، اور فارمز میں واضح لیبلز اور توثیق کی رائے ہونی چاہیے۔

مضبوط: مواد کو موجودہ اور مستقبل کی معاون ٹیکنالوجیز کے ذریعے قابل تشریح ہونا چاہیے۔ اس کا مطلب ہے درست HTML، مناسب ARIA استعمال، اور اسٹیٹس کے پیغامات جن کا اعلان توجہ کی ضرورت کے بغیر کیا جاتا ہے۔


سیمنٹک ایچ ٹی ایم ایل پہلے

سیمنٹک ایچ ٹی ایم ایل واحد سب سے زیادہ لیوریج قابل رسائی سرمایہ کاری ہے۔ مقامی HTML عناصر بلٹ ان ایکسیسبیلٹی رولز، اسٹیٹس، اور کی بورڈ رویے کے ساتھ آتے ہیں — کسی ARIA کی ضرورت نہیں ہے۔

// BAD: Generic divs with no semantics
<div class="button" onclick="submit()">Submit</div>
<div class="nav">
  <div class="link" onclick="navigate('/home')">Home</div>
</div>

// GOOD: Native semantics, free keyboard and screen reader support
<button type="submit" onClick={submit}>Submit</button>
<nav aria-label="Main navigation">
  <a href="/home">Home</a>
</nav>

لینڈ مارک ریجنز اسکرین ریڈر صارفین کو حصوں کے درمیان کود کر تیزی سے نیویگیٹ کرنے میں مدد کرتے ہیں:

// Every page should have these landmarks
<header>        {/* banner landmark */}
  <nav aria-label="Main">...</nav>
</header>
<main>           {/* main landmark */}
  <h1>Page Title</h1>
  <article>...</article>
  <aside aria-label="Related content">...</aside>
</main>
<footer>         {/* contentinfo landmark */}
  <nav aria-label="Footer">...</nav>
</footer>

سرخی کا درجہ بندی منطقی اور غیر منقطع ہونی چاہیے:

// BAD: Skipped heading levels
<h1>Page Title</h1>
<h3>Section</h3>  {/* Skipped h2! */}

// GOOD: Sequential hierarchy
<h1>Page Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>

رنگ کا تضاد

WCAG 2.1 AA کی ضرورت ہے:

  • 4.5:1 نارمل ٹیکسٹ کے لیے کنٹراسٹ ریشو (18pt / 14pt بولڈ سے نیچے)
  • 3:1 بڑے متن کے لیے متضاد تناسب (18pt+ / 14pt+ بولڈ)
  • 3:1 UI اجزاء اور گرافیکل اشیاء کے لیے (بٹن، شبیہیں، ان پٹ بارڈرز)
// Tailwind color contrast examples
// FAIL: gray-400 on white (#9ca3af on #fff = 2.8:1)
<p className="text-gray-400">This fails AA</p>

// PASS: gray-700 on white (#374151 on #fff = 10.7:1)
<p className="text-gray-700">This passes AA</p>

// For dark mode, test both themes separately
<p className="text-gray-700 dark:text-gray-300">
  gray-700 on white (10.7:1) / gray-300 on gray-900 (9.2:1)
</p>

ترقی کے دوران WebAIM کنٹراسٹ چیکر یا براؤزر DevTools کنٹراسٹ ٹول استعمال کریں۔ رجعت کو پکڑنے کے لیے اسے اپنی اسٹوری بک یا ڈیزائن ٹوکن سسٹم میں شامل کریں:

// contrast-checker.ts
import { getContrast } from 'polished';

function assertContrast(fg: string, bg: string, level: 'AA' | 'AAA' = 'AA') {
  const ratio = getContrast(fg, bg);
  const required = level === 'AA' ? 4.5 : 7;
  if (ratio < required) {
    throw new Error(
      `Contrast ratio ${ratio.toFixed(2)}:1 fails WCAG ${level} (requires ${required}:1)`
    );
  }
}

کی بورڈ نیویگیشن

ہر انٹرایکٹو عنصر — لنکس، بٹن، فارم فیلڈز، حسب ضرورت ویجیٹس — کی بورڈ کے ذریعے قابل رسائی اور قابل عمل ہونا چاہیے۔

فوکس مینجمنٹ

// Skip link: first element on every page
// Allows keyboard users to jump past navigation
export function SkipLink() {
  return (
    <a
      href="#main-content"
      className="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4
                 focus:z-50 focus:px-4 focus:py-2 focus:bg-blue-600 focus:text-white
                 focus:rounded focus:ring-2 focus:ring-white"
    >
      Skip to main content
    </a>
  );
}

// Main content target
<main id="main-content" tabIndex={-1}>
  {/* tabIndex={-1} allows programmatic focus without appearing in tab order */}

موڈلز میں فوکس ٹریپنگ

جب کوئی ڈائیلاگ کھلتا ہے، تو فوکس اس کے اندر پھنس جانا چاہیے۔ بند ہونے پر، توجہ محرک پر واپس آجاتی ہے:

// focus-trap.tsx using @radix-ui/react-focus-trap (used internally by shadcn Dialog)
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog';
import { useRef } from 'react';

export function AccessibleModal({ trigger, children, title }: Props) {
  const triggerRef = useRef<HTMLButtonElement>(null);

  return (
    <Dialog>
      <DialogTrigger ref={triggerRef} asChild>
        <button>Open</button>
      </DialogTrigger>
      <DialogContent
        // shadcn Dialog handles focus trap and returns focus to trigger on close
        aria-describedby="dialog-description"
      >
        <DialogTitle>{title}</DialogTitle>
        <p id="dialog-description" className="sr-only">
          {/* Screen reader description of dialog purpose */}
        </p>
        {children}
      </DialogContent>
    </Dialog>
  );
}

مرئی فوکس انڈیکیٹرز

WCAG 2.1 SC 2.4.11 (WCAG 2.2 میں AA) کو کم از کم 2px فوکس آؤٹ لائن کی ضرورت ہے۔ کسی متبادل کے بغیر توجہ کو کبھی نہ دبائیں:

/* globals.css */
/* NEVER do this: */
:focus { outline: none; }

/* DO this: custom, visible focus ring */
:focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
  border-radius: 4px;
}

/* Remove for mouse users (only show for keyboard) */
:focus:not(:focus-visible) {
  outline: none;
}

ARIA: اسے کب اور کیسے استعمال کیا جائے۔

ARIA (Accessible Rich Internet Applications) کے اوصاف اس بات میں ترمیم کرتے ہیں کہ کس طرح معاون ٹیکنالوجیز DOM کی تشریح کرتی ہیں۔ ARIA کا پہلا اصول: **اگر آپ کے استعمال کے کیس کے لیے مقامی HTML عنصر موجود ہے تو اسے استعمال نہ کریں۔

ARIA لیبلز

// Icon-only button — screen reader has nothing to announce without aria-label
<button aria-label="Close dialog">
  <X className="h-4 w-4" aria-hidden="true" />
</button>

// Form field with visible label — use htmlFor, not aria-label
<label htmlFor="email">Email address</label>
<input id="email" type="email" />

// Input with visible description
<input
  id="password"
  type="password"
  aria-describedby="password-requirements"
/>
<p id="password-requirements">Must be at least 12 characters.</p>

ARIA لائیو ریجنز

توجہ مرکوز کیے بغیر متحرک مواد کی تبدیلیوں کا اعلان کریں:

// Status messages (search results count, form submission status)
function SearchResults({ count, loading }: Props) {
  return (
    <>
      {/* aria-live="polite" waits for user to finish current action */}
      <div aria-live="polite" aria-atomic="true" className="sr-only">
        {loading ? 'Loading results...' : `${count} results found`}
      </div>
      {/* Visual result count (not for screen readers — aria-hidden) */}
      <span aria-hidden="true">{count} results</span>
    </>
  );
}

// Error messages (aria-live="assertive" interrupts immediately)
function FormError({ error }: { error: string | null }) {
  return (
    <div
      role="alert"
      aria-live="assertive"
      className={cn('text-red-500 text-sm', !error && 'hidden')}
    >
      {error}
    </div>
  );
}

اپنی مرضی کے ویجیٹس کے لیے ARIA

جب آپ کو ایک حسب ضرورت ویجیٹ (ٹیب پینل، ٹری ویو، کومبو باکس) بنانا ہوگا، تو ARIA تصنیف کی مشق گائیڈ (APG) کے نمونوں پر بالکل عمل کریں:

// Accessible tabs (ARIA tab pattern)
export function Tabs({ items }: { items: Tab[] }) {
  const [active, setActive] = useState(0);

  return (
    <div>
      <div role="tablist" aria-label="Content tabs">
        {items.map((item, i) => (
          <button
            key={item.id}
            role="tab"
            aria-selected={active === i}
            aria-controls={`panel-${item.id}`}
            id={`tab-${item.id}`}
            tabIndex={active === i ? 0 : -1} // Roving tabindex
            onClick={() => setActive(i)}
            onKeyDown={(e) => {
              if (e.key === 'ArrowRight') setActive((active + 1) % items.length);
              if (e.key === 'ArrowLeft') setActive((active - 1 + items.length) % items.length);
            }}
          >
            {item.label}
          </button>
        ))}
      </div>
      {items.map((item, i) => (
        <div
          key={item.id}
          role="tabpanel"
          id={`panel-${item.id}`}
          aria-labelledby={`tab-${item.id}`}
          hidden={active !== i}
        >
          {item.content}
        </div>
      ))}
    </div>
  );
}

فارم اور ایرر ہینڈلنگ

قابل رسائی شکلیں علمی اور موٹر معذوری والے صارفین کے لیے سب سے زیادہ اثر انداز ہونے والی اصلاحات میں سے ہیں۔

// Accessible form field with error state
function TextField({
  id,
  label,
  error,
  required,
  hint,
  ...props
}: TextFieldProps) {
  const hintId = hint ? `${id}-hint` : undefined;
  const errorId = error ? `${id}-error` : undefined;
  const describedBy = [hintId, errorId].filter(Boolean).join(' ') || undefined;

  return (
    <div>
      <label htmlFor={id} className="font-medium">
        {label}
        {required && <span aria-hidden="true" className="text-red-500 ml-1">*</span>}
        {required && <span className="sr-only">(required)</span>}
      </label>

      {hint && (
        <p id={hintId} className="text-sm text-gray-500 mt-1">
          {hint}
        </p>
      )}

      <input
        id={id}
        aria-required={required}
        aria-invalid={!!error}
        aria-describedby={describedBy}
        className={cn('input', error && 'border-red-500')}
        {...props}
      />

      {error && (
        <p id={errorId} className="text-sm text-red-500 mt-1" role="alert">
          {error}
        </p>
      )}
    </div>
  );
}

تصاویر اور میڈیا

// Informative image
<img src="/chart.png" alt="Bar chart showing 40% revenue growth in Q4 2025" />

// Decorative image — empty alt hides it from screen readers
<img src="/divider.png" alt="" role="presentation" />

// Complex image — use aria-describedby for long descriptions
<figure>
  <img
    src="/architecture.png"
    alt="System architecture diagram"
    aria-describedby="arch-desc"
  />
  <figcaption id="arch-desc">
    The diagram shows three tiers: frontend Next.js on port 3000,
    NestJS API on port 3001, and PostgreSQL database on port 5433.
    Redis sits between the API and database layers.
  </figcaption>
</figure>

// SVG icons used as decoration
<svg aria-hidden="true" focusable="false">
  <use href="#icon-search" />
</svg>

ایکس کور کے ساتھ خودکار ٹیسٹنگ

pnpm add -D @axe-core/playwright axe-core
// tests/a11y/homepage.spec.ts
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

test.describe('Homepage accessibility', () => {
  test('should have no WCAG 2.1 AA violations', async ({ page }) => {
    await page.goto('/');

    const results = await new AxeBuilder({ page })
      .withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
      .exclude('#third-party-widget') // Exclude known external violations
      .analyze();

    expect(results.violations).toEqual([]);
  });

  test('should be keyboard navigable', async ({ page }) => {
    await page.goto('/');
    // Tab through interactive elements and verify focus is visible
    await page.keyboard.press('Tab');
    const focusedElement = await page.evaluate(
      () => document.activeElement?.getAttribute('href')
    );
    expect(focusedElement).toBe('#main-content'); // Skip link
  });
});

CI پائپ لائن میں شامل کریں:

# .github/workflows/ci.yml
- name: Run accessibility tests
  run: cd apps/web && npx playwright test tests/a11y --reporter=html
- uses: actions/upload-artifact@v4
  with:
    name: a11y-report
    path: apps/web/playwright-report/

اکثر پوچھے گئے سوالات

WCAG 2.1 A، AA، اور AAA میں کیا فرق ہے؟

لیول A کم از کم ہے — لیول A میں ناکام ہونے کا مطلب ہے کہ مواد بنیادی طریقوں سے کچھ صارفین کے لیے ناقابل رسائی ہے۔ لیول AA زیادہ تر دائرہ اختیار میں قانونی معیار ہے اور صارف کی وسیع تر ضروریات کو نشانہ بناتا ہے۔ سطح AAA خواہش مند ہے — کچھ معیار تمام مواد کی اقسام کے لیے پورے نہیں کیے جا سکتے۔ AA کی تعمیل کو اپنی بنیادی لائن کے طور پر ہدف بنائیں اور جہاں عملی ہو وہاں AAA کا مقصد بنائیں۔

کیا shadcn/ui جیسی جزو لائبریری کا استعمال میری ایپ کو قابل رسائی بناتا ہے؟

shadcn/ui Radix UI پرائمیٹوز پر بنایا گیا ہے، جو ڈیزائن کے ذریعے قابل رسائی ہیں — ان میں درست ARIA رولز، کی بورڈ نیویگیشن، اور فوکس مینجمنٹ شامل ہیں۔ تاہم، آپ کو اب بھی بامعنی لیبلز شامل کرنے، غلطی کی حالتوں کو قابل رسائی طریقے سے ہینڈل کرنے، اپنی مرضی کے مطابق تھیم کے ساتھ کافی رنگ کے تضاد کو یقینی بنانے، اور حقیقی معاون ٹیکنالوجیز کے ساتھ ٹیسٹ کرنے کی ضرورت ہے۔ اجزاء کی لائبریریاں بوجھ کو کم کرتی ہیں لیکن رسائی کی جانچ کی ضرورت کو ختم نہیں کرتی ہیں۔

میں اسکرین ریڈر کے ساتھ کیسے ٹیسٹ کروں؟

ونڈوز پر، فائر فاکس یا کروم کے ساتھ NVDA (مفت) استعمال کریں۔ macOS پر، Safari کے ساتھ VoiceOver (بلٹ ان، Cmd+F5) استعمال کریں۔ موبائل پر، TalkBack (Android) یا VoiceOver (iOS) استعمال کریں۔ اہم صارف کے سفر کی جانچ کریں: فارم کی تکمیل، موڈل تعاملات، نشانات کے ذریعے نیویگیشن، اور متحرک مواد پڑھنا۔ اسکرین ریڈر ٹیسٹنگ اعلانات، پڑھنے کی ترتیب، اور فوکس رویے کو پکڑتا ہے جو خودکار ٹولز سے محروم رہتے ہیں۔

Roving tabindex پیٹرن کیا ہے؟

Roving tabindex جامع وجیٹس (ٹیب کی فہرستیں، ٹول بار، ریڈیو گروپس، درخت کے نظارے) کے لیے کی بورڈ پیٹرن ہے۔ گروپ میں صرف ایک آئٹم میں ایک وقت میں tabIndex={0} ہوتا ہے — ایکٹو آئٹم۔ باقی سبھی کو tabIndex={-1} ملتا ہے۔ ایرو کیز گروپ کے اندر فوکس کو منتقل کرتی ہیں اور اپ ڈیٹ کرتی ہیں کہ کس آئٹم میں ٹیب انڈیکس 0 ہے۔ یہ صارف کو گروپ میں ہر آئٹم کے ذریعے ٹیب کرنے سے روکتا ہے - وہ ٹیب کے ساتھ گروپ میں داخل ہوتے ہیں، ایرو کیز کے ساتھ نیویگیٹ کرتے ہیں، اور ٹیب کے ساتھ چلے جاتے ہیں۔

میں AJAX کے ذریعے لوڈ کیے گئے متحرک مواد کے لیے رسائی کو کیسے ہینڈل کروں؟

اسٹیٹس اپ ڈیٹس کے لیے aria-live علاقوں کا استعمال کریں (تلاش کے نتائج شمار، تصدیقات محفوظ کریں)۔ پورے صفحہ کے حصے کی تبدیلی کے لیے، لوڈ ہونے کے بعد نئے مواد کی سرخی یا کنٹینر پر توجہ مرکوز کریں۔ لوڈنگ ریاستوں کے لیے، اپ ڈیٹ کیے جانے والے خطے پر aria-busy="true" اور تکمیل کا اعلان کرنے کے لیے aria-live="polite" خطہ استعمال کریں۔ اعلانات واضح اور بروقت ہونے کی تصدیق کے لیے ہمیشہ اسکرین ریڈر کے ساتھ ٹیسٹ کریں۔


اگلے اقدامات

ویب تک رسائی ایک جاری عمل ہے، ایک بار کا آڈٹ نہیں۔ اپنے سیمنٹک ایچ ٹی ایم ایل اور کلر کنٹراسٹ کو ٹھیک کرکے شروع کریں، پھر پیچیدہ ویجیٹس کے لیے کی بورڈ نیویگیشن اور ARIA میں پرت لگائیں، اور ریگریشنز کو پکڑنے کے لیے اپنی CI پائپ لائن میں WCAG کی توثیق کو خودکار کریں۔

ECOSIRE WCAG 2.1 AA کے مطابق ویب ایپلیکیشنز کو ہر پروجیکٹ پر ایک بنیادی معیار کے طور پر بناتا ہے۔ اگر آپ کو ایکسیسبیلٹی آڈٹ کی ضرورت ہے یا آپ کو زمین سے مطابقت پیدا کرنا چاہتے ہیں، ہماری فرنٹ اینڈ انجینئرنگ سروسز کو دریافت کریں۔

E

تحریر

ECOSIRE Research and Development Team

ECOSIRE میں انٹرپرائز گریڈ ڈیجیٹل مصنوعات بنانا۔ Odoo انٹیگریشنز، ای کامرس آٹومیشن، اور AI سے چلنے والے کاروباری حل پر بصیرت شیئر کرنا۔

Chat on WhatsApp