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.4k शब्द|

हमारी Compliance & Regulation श्रृंखला का हिस्सा

पूरी गाइड पढ़ें

वेब एक्सेसिबिलिटी: WCAG 2.1 AA अनुपालन गाइड

एक्सेसिबिलिटी कोई ऐसी सुविधा नहीं है जिसे आप लॉन्च के बाद जोड़ते हैं - यह एक मौलिक गुणवत्ता विशेषता है, जो प्रदर्शन या सुरक्षा के समान है। WCAG 2.1 AA अनुपालन अब EU (यूरोपीय एक्सेसिबिलिटी एक्ट, जून 2025 में लागू), अमेरिका (ADA टाइटल III केस कानून), और कई अन्य न्यायालयों में कानूनी रूप से आवश्यक है। अनुपालन से परे, सुलभ इंटरफ़ेस बेहतर रूपांतरण करते हैं, खोज में उच्च रैंक करते हैं, और दुनिया भर में विकलांगों के साथ अनुमानित 1.3 बिलियन लोगों की सेवा करते हैं।

यह मार्गदर्शिका एक व्यावहारिक कार्यान्वयन मैनुअल है, चेकलिस्ट नहीं। आप चार डब्ल्यूसीएजी सिद्धांतों, सबसे प्रभावशाली तकनीकों, व्यवस्थित रूप से परीक्षण कैसे करें, और अपने रिएक्ट/नेक्स्ट.जेएस विकास वर्कफ़्लो में पहुंच को कैसे एकीकृत करें, सीखेंगे ताकि यह स्थिर रहे।

मुख्य बातें

  • WCAG 2.1 AA को सभी चार POUR सिद्धांतों की आवश्यकता है: बोधगम्य, संचालन योग्य, समझने योग्य, मजबूत
  • सिमेंटिक HTML से प्रारंभ करें - यह किसी भी ARIA को जोड़ने से पहले 70% पहुंच निःशुल्क प्रदान करता है
  • न्यूनतम रंग कंट्रास्ट अनुपात: सामान्य पाठ के लिए 4.5:1, बड़े पाठ के लिए 3:1 (18पी/14पीटी बोल्ड)
  • प्रत्येक इंटरैक्टिव तत्व दृश्यमान फोकस संकेतक के साथ कीबोर्ड पर फोकस करने योग्य होना चाहिए
  • स्क्रीन रीडर्स एक्सेसिबिलिटी ट्री के आधार पर घोषणा करते हैं - एनवीडीए (विंडोज) और वॉयसओवर (मैक) के साथ परीक्षण
  • ARIA एक अंतिम उपाय है - यह केवल बदलता है कि सहायक प्रौद्योगिकियाँ DOM की व्याख्या कैसे करती हैं, व्यवहार में नहीं
  • अपने सीआई पाइपलाइन में एक्स-कोर के साथ स्वचालित करें; मैन्युअल परीक्षण से पता चल जाता है कि स्वचालन में क्या कमी रह गई है
  • अपने पहुंच विवरण का दस्तावेजीकरण करें और उपयोगकर्ताओं को समस्याओं की रिपोर्ट करने के लिए एक फीडबैक तंत्र प्रदान करें

चार पौर सिद्धांत

WCAG 2.1 को चार सिद्धांतों के आधार पर व्यवस्थित किया गया है। सफलता की प्रत्येक कसौटी उनमें से किसी एक की होती है।

बोधगम्य: जानकारी इस प्रकार प्रस्तुत करने योग्य होनी चाहिए कि उपयोगकर्ता इसे समझ सकें। इसमें छवियों के लिए पाठ विकल्प, वीडियो के लिए कैप्शन, पर्याप्त रंग कंट्रास्ट और ऐसी सामग्री शामिल है जो अर्थ बताने के लिए केवल रंग पर निर्भर नहीं है।

संचालित: सभी कार्यक्षमताएं कीबोर्ड के माध्यम से संचालित होनी चाहिए, बातचीत करने के लिए पर्याप्त समय होना चाहिए, कोई जब्ती-ट्रिगर करने वाली सामग्री नहीं होनी चाहिए, और नेविगेशन योग्य संरचना (लिंक छोड़ें, पृष्ठ शीर्षक, फोकस ऑर्डर) होनी चाहिए।

समझने योग्य: सामग्री पठनीय और पूर्वानुमानित होनी चाहिए। भाषा की पहचान होनी चाहिए, त्रुटि संदेश वर्णनात्मक होने चाहिए, और प्रपत्रों में स्पष्ट लेबल और सत्यापन प्रतिक्रिया होनी चाहिए।

मजबूत: सामग्री वर्तमान और भविष्य की सहायक तकनीकों द्वारा व्याख्या योग्य होनी चाहिए। इसका मतलब है वैध HTML, उचित ARIA उपयोग और स्थिति संदेश जो बिना फोकस की आवश्यकता के घोषित किए जाते हैं।


सिमेंटिक HTML प्रथम

सिमेंटिक HTML एकल उच्चतम-लीवरेज एक्सेसिबिलिटी निवेश है। मूल 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 सामान्य पाठ के लिए कंट्रास्ट अनुपात (18 अंक से कम / 14 अंक बोल्ड)
  • 3:1 बड़े टेक्स्ट के लिए कंट्रास्ट अनुपात (18pt+ / 14pt+ बोल्ड)
  • 3:1 यूआई घटकों और ग्राफिकल ऑब्जेक्ट्स (बटन, आइकन, इनपुट बॉर्डर) के लिए
// 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 (एक्सेसिबल रिच इंटरनेट एप्लिकेशन) विशेषताएँ संशोधित करती हैं कि सहायक प्रौद्योगिकियाँ 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
  });
});

सीआई पाइपलाइन में जोड़ें:

# .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/

अक्सर पूछे जाने वाले प्रश्न

डब्ल्यूसीएजी 2.1 ए, एए और एएए के बीच क्या अंतर है?

स्तर ए न्यूनतम है - स्तर ए के विफल होने का मतलब है कि सामग्री मौलिक तरीकों से कुछ उपयोगकर्ताओं के लिए पहुंच योग्य नहीं है। स्तर एए अधिकांश न्यायक्षेत्रों में कानूनी मानक है और व्यापक उपयोगकर्ता आवश्यकताओं को लक्षित करता है। स्तर एएए आकांक्षी है - सभी सामग्री प्रकारों के लिए कुछ मानदंड पूरे नहीं किए जा सकते। एए अनुपालन को अपनी आधार रेखा के रूप में लक्षित करें और जहां व्यावहारिक हो वहां एएए का लक्ष्य रखें।

क्या shadcn/ui जैसी घटक लाइब्रेरी का उपयोग करने से मेरा ऐप पहुंच योग्य हो जाता है?

shadcn/ui रेडिक्स यूआई प्राइमेटिव्स पर बनाया गया है, जो डिज़ाइन द्वारा पहुंच योग्य हैं - इनमें सही ARIA भूमिकाएं, कीबोर्ड नेविगेशन और फोकस प्रबंधन शामिल हैं। हालाँकि, आपको अभी भी सार्थक लेबल जोड़ने, त्रुटि स्थितियों को आसानी से संभालने, अपने कस्टम थीम के साथ पर्याप्त रंग कंट्रास्ट सुनिश्चित करने और वास्तविक सहायक प्रौद्योगिकियों के साथ परीक्षण करने की आवश्यकता है। घटक पुस्तकालय बोझ को कम करते हैं लेकिन पहुंच-योग्यता परीक्षण की आवश्यकता को समाप्त नहीं करते हैं।

मैं स्क्रीन रीडर के साथ परीक्षण कैसे करूं?

विंडोज़ पर, फ़ायरफ़ॉक्स या क्रोम के साथ एनवीडीए (निःशुल्क) का उपयोग करें। MacOS पर, Safari के साथ VoiceOver (अंतर्निहित, Cmd+F5) का उपयोग करें। मोबाइल पर, टॉकबैक (एंड्रॉइड) या वॉयसओवर (आईओएस) का उपयोग करें। प्रमुख उपयोगकर्ता यात्राओं का परीक्षण करें: फॉर्म पूरा करना, मोडल इंटरैक्शन, स्थलों के माध्यम से नेविगेशन, और गतिशील सामग्री पढ़ना। स्क्रीन रीडर परीक्षण घोषणाओं, पढ़ने के क्रम और फोकस व्यवहार को पकड़ता है जो स्वचालित उपकरण चूक जाते हैं।

रोविंग टैबिंडेक्स पैटर्न क्या है?

रोविंग टैबिंडेक्स समग्र विजेट (टैब सूचियाँ, टूलबार, रेडियो समूह, ट्री व्यू) के लिए कीबोर्ड पैटर्न है। समूह में एक समय में केवल एक आइटम में tabIndex={0} होता है - सक्रिय आइटम। अन्य सभी को tabIndex={-1} मिलता है। एरो कुंजियाँ समूह के भीतर फोकस को स्थानांतरित करती हैं और अपडेट करती हैं कि किस आइटम में टैब इंडेक्स 0 है। यह उपयोगकर्ता को समूह में प्रत्येक आइटम के माध्यम से टैब करने से रोकता है - वे टैब के साथ समूह में प्रवेश करते हैं, एरो कुंजियों के साथ नेविगेट करते हैं, और टैब के साथ छोड़ देते हैं।

मैं AJAX के माध्यम से लोड की गई गतिशील सामग्री की पहुंच कैसे संभालूं?

स्थिति अपडेट के लिए aria-live क्षेत्रों का उपयोग करें (खोज परिणाम गिनती, पुष्टिकरण सहेजें)। पूर्ण पृष्ठ अनुभाग प्रतिस्थापन के लिए, लोड करने के बाद फोकस को नई सामग्री के शीर्षक या कंटेनर पर ले जाएँ। राज्यों को लोड करने के लिए, अद्यतन किए जा रहे क्षेत्र पर aria-busy="true" और पूर्णता की घोषणा करने के लिए aria-live="polite" क्षेत्र का उपयोग करें। घोषणाओं को स्पष्ट और समय पर सत्यापित करने के लिए हमेशा स्क्रीन रीडर से परीक्षण करें।


अगले चरण

वेब एक्सेसिबिलिटी एक सतत प्रक्रिया है, एक बार का ऑडिट नहीं। अपने सिमेंटिक HTML और कलर कंट्रास्ट को ठीक करके शुरुआत करें, फिर जटिल विजेट्स के लिए कीबोर्ड नेविगेशन और ARIA को परत करें, और रिग्रेशन को पकड़ने के लिए अपने CI पाइपलाइन में WCAG सत्यापन को स्वचालित करें।

ECOSIRE प्रत्येक प्रोजेक्ट पर बेसलाइन मानक के रूप में WCAG 2.1 AA अनुरूप वेब एप्लिकेशन बनाता है। यदि आपको एक्सेसिबिलिटी ऑडिट की आवश्यकता है या आप जमीनी स्तर से अनुरूप निर्माण करना चाहते हैं, हमारी फ्रंटएंड इंजीनियरिंग सेवाओं का पता लगाएं

शेयर करें:
E

लेखक

ECOSIRE Research and Development Team

ECOSIRE में एंटरप्राइज़-ग्रेड डिजिटल उत्पाद बना रहे हैं। Odoo एकीकरण, ई-कॉमर्स ऑटोमेशन, और AI-संचालित व्यावसायिक समाधानों पर अंतर्दृष्टि साझा कर रहे हैं।

WhatsApp पर चैट करें